简体   繁体   English

如何缩小我的 SQL Server 数据库?

[英]How do I shrink my SQL Server Database?

I have a Database nearly 1.9Gb Database in size, and MSDE2000 does not allow DBs that exceed 2.0Gb我有一个大小接近 1.9Gb 的数据库,并且 MSDE2000 不允许超过 2.0Gb 的数据库

I need to shrink this DB (and many others like this at various client locations).我需要缩小这个数据库(以及在不同客户端位置的许多其他数据库)。

I have found and deleted many 100's of 1000's of records which are considered unneeded: these records account for a large percentage of some of the main (largest) tables in the Database.我发现并删除了 1000 条被认为不需要的记录:这些记录占数据库中一些主要(最大)表的很大比例。 Therefore it's reasonable to assume much space should now be retrievable.因此,假设现在应该可以检索很多空间是合理的。

So now I need to shrink the DB to account for the missing records.所以现在我需要缩小数据库以解决丢失的记录。

  • I execute DBCC ShrinkDatabase('MyDB') ...... No effect.我执行DBCC ShrinkDatabase('MyDB') ...... 没有效果。
  • I have tried the various shrink facilities provided in MSSMS.... Still no effect.我已经尝试了 MSSMS 中提供的各种收缩工具......仍然没有效果。
  • I have backed up the database and restored it... Still no effect.我已经备份了数据库并恢复了它......仍然没有效果。

Still 1.9Gb还是 1.9Gb

Why?为什么?

Whatever procedure I eventually find needs to be replayable on a client machine with access to nothing other than OSql or similar.我最终发现的任何过程都需要在客户端机器上重放,只能访问 OSql 或类似的东西。

ALTER DATABASE MyDatabase SET RECOVERY SIMPLE

GO

DBCC SHRINKFILE (MyDatabase_Log, 5)

GO

ALTER DATABASE MyDatabase SET RECOVERY FULL

GO

This may seem bizarre, but it's worked for me and I have written a C# program to automate this.这可能看起来很奇怪,但它对我有用,我已经编写了一个 C# 程序来自动执行此操作。

Step 1: Truncate the transaction log (Back up only the transaction log, turning on the option to remove inactive transactions)第 1 步:截断事务日志(仅备份事务日志,打开删除非活动事务的选项)

Step 2: Run a database shrink, moving all the pages to the start of the files步骤 2:运行数据库收缩,将所有页面移动到文件的开头

Step 3: Truncate the transaction log again, as step 2 adds log entries第 3 步:再次截断事务日志,因为第 2 步添加了日志条目

Step 4: Run a database shrink again.第 4 步:再次运行数据库收缩。

My stripped down code, which uses the SQL DMO library, is as follows:我使用 SQL DMO 库的精简代码如下:

SQLDatabase.TransactionLog.Truncate();
SQLDatabase.Shrink(5, SQLDMO.SQLDMO_SHRINK_TYPE.SQLDMOShrink_NoTruncate);
SQLDatabase.TransactionLog.Truncate();
SQLDatabase.Shrink(5, SQLDMO.SQLDMO_SHRINK_TYPE.SQLDMOShrink_Default);

This is an old question but I just happened upon it.这是一个古老的问题,但我刚刚遇到它。

The really short and a correct answer is already given and has the most votes.真正简短且正确的答案已经给出,并且拥有最多的选票。 That is how you shrink a transaction log, and that was probably the OPs problem.那你是怎么收缩事务日志,这很可能是有机磷农药的问题。 And when the transaction log has grown out of control, it often needs to be shrunk back, but care should be taken to prevent future situations of a log growing out of control.并且当事务日志增长失控时,通常需要将其缩回,但应注意防止日志增长失控的未来情况。 This question on dba.se explains that. dba.se上的这个问题解释了这一点。 Basically - Don't let it get that large in the first place through proper recovery model, transaction log maintenance, transaction management, etc.基本上 - 首先不要让它通过适当的恢复模型、事务日志维护、事务管理等变得那么大。

But the bigger question in my mind when reading this question about shrinking the data file (or even the log file) is why?但是在阅读这个关于缩小数据文件(甚至日志文件)的问题时,我脑海中更大的问题是为什么? and what bad things happen when you try?当你尝试时会发生什么不好的事情? It appears as though shrink operations were done.看起来好像完成了收缩操作。 Now in this case it makes sense in a sense - because MSDE/Express editions are capped at max DB size.现在在这种情况下,它在某种意义上是有意义的 - 因为 MSDE/Express 版本的上限为最大数据库大小。 But the right answer may be to look at the right version for your needs.但正确的答案可能是根据您的需要查看正确的版本。 And if you stumble upon this question looking to shrink your production database and this isn't the reason why, you should ask yourself the why?如果您偶然发现了这个想要缩小生产数据库的问题,而这不是原因,那么您应该问问自己为什么? question.题。

I don't want someone searching the web for "how to shrink a database" coming across this and thinking it is a cool or acceptable thing to do.我不希望有人在网上搜索“如何缩小数据库”时遇到这个问题,并认为这是一件很酷或可以接受的事情。

Shrinking Data Files is a special task that should be reserved for special occasions.收缩数据文件是一项特殊任务,应保留用于特殊场合。 Consider that when you shrink a database, you are effectively fragmenting your indexes.考虑到当您收缩数据库时,您实际上是在分割索引。 Consider that when you shrink a database you are taking away the free space that a database may someday grow right back into - effectively wasting your time and incurring the performance hit of a shrink operation only to see the DB grow again.考虑到当您收缩数据库时,您正在占用数据库可能有一天会重新增长的可用空间 - 有效地浪费了您的时间并招致收缩操作的性能损失,只是为了看到数据库再次增长。

I wrote about this concept in several blog posts about shrinking databases.我在几篇关于缩小数据库的博客文章中写过这个概念。 This one called " Don't touch that shrink button " comes to mind first.第一个想到的就是不要碰那个收缩按钮”。 I talk about these concepts outlined here - but also the concept of "Right-Sizing" your database.我谈论这里概述的这些概念 - 以及“适当调整”数据库的概念。 It is far better to decide what your database size needs to be, plan for future growth and allocate it to that amount.最好确定您的数据库大小需要,计划未来增长并将其分配到该数量。 With Instant File Initialization available in SQL Server 2005 and beyond for data files, the cost of growths is lower - but I still prefer to have a proper initial application - and I'm far less scared of white space in a database than I am of shrinking in general with no thought first.在 SQL Server 2005 及更高版本中为数据文件提供即时文件初始化,增长的成本较低 - 但我仍然更喜欢有一个适当的初始应用程序 - 并且我对数据库中的空白远不那么害怕一般不加思索地缩小。 :) :)

DBCC SHRINKDATABASE works for me, but this is its full syntax: DBCC SHRINKDATABASE对我DBCC SHRINKDATABASE ,但这是它的完整语法:

DBCC SHRINKDATABASE ( database_name, [target_percent], [truncate] )

where target_percent is the desired percentage of free space left in the database file after the database has been shrunk.其中target_percent是数据库收缩后数据库文件中剩余可用空间的所需百分比。

And truncate parameter can be: truncate参数可以是:

NOTRUNCATE

Causes the freed file space to be retained in the database files.使释放的文件空间保留在数据库文件中。 If not specified, the freed file space is released to the operating system.如果未指定,则释放的文件空间将释放给操作系统。

TRUNCATEONLY

Causes any unused space in the data files to be released to the operating system and shrinks the file to the last allocated extent, reducing the file size without moving any data.将数据文件中任何未使用的空间释放给操作系统,并将文件缩小到最后分配的范围,在不移动任何数据的情况下减小文件大小。 No attempt is made to relocate rows to unallocated pages.不会尝试将行重定位到未分配的页面。 target_percent is ignored when TRUNCATEONLY is used.使用 TRUNCATEONLY 时会忽略 target_percent。

...and yes no_one is right, shrinking datbase is not very good practice becasue for example : ...是的 no_one 是对的,缩小数据库不是很好的做法,因为例如:

shrink on data files are excellent ways to introduce significant logical fragmentation, becasue it moves pages from the end of the allocated range of a database file to somewhere at the front of the file...缩小数据文件是引入显着逻辑碎片的极好方法,因为它将页面从数据库文件分配范围的末尾移动到文件前面的某个位置...

shrink database can have a lot of consequence on database, server.... think a lot about it before you do it!收缩数据库会对数据库、服务器产生很大的影响......在你做之前想很多!

on the web there are a lot of blogs and articles about it.在网络上有很多关于它的博客和文章。

Late answer but might be useful useful for someone else迟到的答案,但可能对其他人有用

If neither DBCC ShrinkDatabase/ShrinkFile or SSMS (Tasks/Shrink/Database) doesn't help, there are tools from Quest and ApexSQL that can get the job done, and even schedule periodic shrinking if you need it.如果 DBCC ShrinkDatabase/ShrinkFile 或 SSMS(任务/收缩/数据库)都无济于事,那么 Quest 和 ApexSQL 的工具可以完成工作,如果需要,甚至可以安排定期收缩。

I've used the latter one in free trial to do this some time ago, by following short description at the end of this article:前段时间我在免费试用中使用了后者来做到这一点,通过在本文末尾进行简短描述:

https://solutioncenter.apexsql.com/sql-server-database-shrink-how-and-when-to-schedule-and-perform-shrinking-of-database-files/ https://solutioncenter.apexsql.com/sql-server-database-shrink-how-and-when-to-schedule-and-perform-shrinking-of-database-files/

All you need to do is install ApexSQL Backup, click "Shrink database" button in the main ribbon, select database in the window that will pop-up, and click "Finish".您需要做的就是安装 ApexSQL Backup,单击主功能区中的“收缩数据库”按钮,在弹出的窗口中选择数据库,然后单击“完成”。

You should use:你应该使用:

dbcc shrinkdatabase (MyDB)

It will shrink the log file (keep a windows explorer open and see it happening).它将缩小日志文件(保持 Windows 资源管理器打开并查看它发生的情况)。

You will also need to shrink the individual data files.您还需要缩小各个数据文件。

It is however not a good idea to shrink the databases.然而,缩小数据库并不是一个好主意。 For example see here例如见这里

"Therefore it's reasonable to assume much space should now be retrievable." “因此,假设现在应该可以收回很多空间是合理的。”

Apologies if I misunderstood the question, but are you sure it's the database and not the log files that are using up the space?抱歉,如果我误解了这个问题,但您确定是数据库而不是日志文件占用了空间吗? Check to see what recovery model the database is in. Chances are it's in Full, which means the log file is never truncated.检查以查看数据库所在的恢复模型。它可能处于完整状态,这意味着日志文件永远不会被截断。 If you don't need a complete record of every transaction, you should be able to change to Simple, which will truncate the logs.如果您不需要每个事务的完整记录,您应该能够更改为简单,这将截断日志。 You can shrink the database during the process.您可以在此过程中缩小数据库。 Assuming things go right, the process looks like:假设一切顺利,过程如下:

  1. Backup the database!备份数据库!
  2. Change to Simple Recovery更改为简单恢复
  3. Shrink db (right-click db, choose all tasks > shrink db -> set to 10% free space) Shrink db(右键db,选择所有任务>收缩db->设置为10%可用空间)
  4. Verify that the space has been reclaimed, if not you might have to do a full backup验证空间是否已被回收,如果没有,您可能需要进行完整备份

If that doesn't work (or you get a message saying "log file is full" when you try to switch recovery modes), try this:如果这不起作用(或者当您尝试切换恢复模式时收到一条消息说“日志文件已满”),请尝试以下操作:

  1. Backup备份
  2. Kill all connections to the db杀死与数据库的所有连接
  3. Detach db (right-click > Detach or right-click > All Tasks > Detach)分离数据库(右键单击 > 分离或右键单击 > 所有任务 > 分离)
  4. Delete the log (ldf) file删除日志(ldf)文件
  5. Reattach the db重新连接数据库
  6. Change the recovery mode更改恢复模式

etc.等等。

Here's another solution: Use the Database Publishing Wizard to export your schema, security and data to sql scripts.这是另一个解决方案:使用数据库发布向导将架构、安全性和数据导出到 sql 脚本。 You can then take your current DB offline and re-create it with the scripts.然后,您可以使当前的数据库脱机并使用脚本重新创建它。

Sounds kind of foolish, but there are a couple advantages.听起来有点愚蠢,但有几个优点。 First, there's no chance of losing data.首先,不会丢失数据。 Your original db (as long as you don't delete your DB when dropping it!) is safe, the new DB will be roughly as small as it can be, and you'll have two different snapshots of your current database - one ready to roll, one minified - you can choose from to back up.您的原始数据库(只要您在删除数据库时不删除它!)是安全的,新数据库将大致尽可能小,并且您将拥有当前数据库的两个不同快照 - 一个准备就绪滚动,一个缩小 - 您可以选择备份。

I came across this post even though I needed to SHRINKFILE on MSSQL 2012 version which is little trickier since 2000 or 2005 versions.尽管我需要在 MSSQL 2012 版本上使用 SHRINKFILE,但我还是看到了这篇文章,这自 2000 或 2005 版本以来就有点棘手了。 After reading up on all risks and issues related to this issue I ended up testing.在阅读了与此问题相关的所有风险和问题后,我最终进行了测试。 Long story short, the best results I got were from using the MS SQL Server Management Studio .长话短说,我得到的最好结果是使用MS SQL Server Management Studio

Right-Click the DB -> TASKS -> SHRINK -> FILES -> select the LOG file

Delete data, make sure recovery model is simple, then skrink (either shrink database or shrink files works).删除数据,确保恢复模式简单,然后收缩(收缩数据库或收缩文件都有效)。 If the data file is still too big, AND you use heaps to store data -- that is, no clustered index on large tables -- then you might have this problem regarding deleting data from heaps: http://support.microsoft.com/kb/913399如果数据文件仍然太大,并且您使用堆来存储数据——也就是说,大表上没有聚集索引——那么您可能会遇到关于从堆中删除数据的问题: http : //support.microsoft.com /kb/913399

Not sure how practical this would be, and depending on the size of the database, number of tables and other complexities, but I:不确定这有多实用,取决于数据库的大小、表的数量和其他复杂性,但我:

  1. defrag the physical drive对物理驱动器进行碎片整理
  2. create a new database according to my requirements, space, percentage growth, etc根据我的要求、空间、增长百分比等创建一个新数据库
  3. use the simple ssms task to import all tables from the old db to the new db使用简单的 ssms 任务将所有表从旧数据库导入到新数据库
  4. script out the indexes for all tables on the old database, and then recreate the indexes on the new database.为旧数据库上的所有表编写索引,然后在新数据库上重新创建索引。 expand as needed for foreign keys etc.根据需要扩展外键等。
  5. rename databases as needed, confirm successful, delete old根据需要重命名数据库,确认成功,删除旧的

You also have to modify the minimum size of the data and log files.您还必须修改数据和日志文件的最小大小。 DBCC SHRINKDATABASE will shrink the data inside the files you already have allocated. DBCC SHRINKDATABASE会收缩里面的文件,你已经分配的数据。 To shrink a file to a size smaller than its minimum size, use DBCC SHRINKFILE and specify the new size.要将文件缩小到小于其最小大小的大小,请使用 DBCC SHRINKFILE 并指定新大小。

I think you can remove all your log with switch from full to simple recovery.我认为您可以通过从完全恢复到简单恢复的切换来删除所有日志。 Right click on your Database and select Properties and select Options and change右键单击您的数据库并选择Properties并选择Options并更改

  • Recovery mode to Simple Recovery modeSimple
  • Containment type to None Containment typeNone

从完整切换到简单

When you've set the recovery model to Simple (and enabled auto-shrink), it is still possible that SQL Server can not shrink the log.当您将恢复模式设置为简单(并启用自动收缩)时,SQL Server 仍有可能无法收缩日志。 It has to do with checkpoints in the log (or lack thereof).它与日志中的检查点(或缺少检查点)有关。

So first run所以第一次运行

DBCC CHECKDB

on your database.在你的数据库上。 After that the shrink operation should work like a charm.之后,收缩操作应该像魅力一样工作。

Usually I use the Tasks>Shrink>Files menu and choose the logfile with the option to reorganise pages.通常我使用任务>收缩>文件菜单并选择带有重新组织页面选项的日志文件。

I recently did this.我最近做了这个。 I was trying to make a compact version of my database for testing on the road, but I just couldn't get it to shrink, no matter how many rows I deleted.我试图制作我的数据库的紧凑版本以在路上进行测试,但无论我删除了多少行,我都无法缩小它。 Eventually, after many other commands in this thread, I found that my clustered indexes were not getting rebuilt after deleting rows.最终,在这个线程中的许多其他命令之后,我发现我的聚集索引在删除行后没有得到重建。 Rebuilding my indexes made it so I could shrink properly.重建我的索引使我可以正确缩小。

DBCC SHRINKFILE(N'YourDatabaseName', 0);

DBCC SHRINKFILE(N'YourDatabaseName_log', 0);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM