この質問は何十回も尋ねられますが、驚いたことに、このような単純な要件は非常に難しくなります。しかし、私はこの問題を解決できません。
SQL Server 2014 Expressエディションを使用しており、データベースサイズが10 GBに制限されています(ファイルグループサイズやデータベースサイズではありません)。
ニュースをクロールし、HTMLをテーブルに挿入しました。テーブルのスキーマは次のとおりです。
Id bigint identity(1, 1) primary key,
Url varchar(250) not null,
OriginalHtml nvarchar(max),
...
データベースのサイズが不足し、insufficient disk space
を受け取りました
もちろん、データベースとファイルグループを縮小しても効果はありませんでした。 DBCC SHRINKDATABASE
は役に立ちませんでした。したがって、各レコードを読み取り、ヘッドセクションやサイドとフッターなどのOriginalHtml
の不要な部分を取り除いて本体のみを保持する単純なアプリケーションを作成しました。ディスクの使用状況のレポートを取得すると、この画像が表示されます。トップテーブル:
この画像を理解すると、未使用のスペースは合計サイズの50%になります。つまり、5GBの未使用スペースができました。しかし、私はそれを取り戻すことはできません。インデックスの再構築は役に立ちませんでした。 truncateonly
オプションは役に立ちません。レコードが削除されないことがわかったので、各レコードのサイズのみが縮小されます。
この時点で行き詰まっています。助けてください、どうしたらいいですか?
クラスタ化インデックスは列Id
にあります。
これはEXECUTE sys.sp_spaceused @objname = N'dbo.Articles', @updateusage = 'true';
の結果です
name rows reserved data index_size unused
----------- -------- ------------ ----------- ------------ -----------
Articles 112258 8079784 KB 5199840 KB 13360 KB 2866584 KB
すべてが同じであれば、ラージオブジェクト(LOB)列OriginalHTML
を圧縮するだけで十分です。質問ではクラスター化インデックス名を指定しないので、次のようにします。
_ALTER INDEX ALL
ON dbo.Articles
REORGANIZE
WITH (LOB_COMPACTION = ON);
_
(クラスター化された列だけでなく)クラスター化インデックス名がある場合は、上記のALL
をその名前に置き換えます。
_LOB_COMPACTION
_オプションのデフォルトはON
ですが、明示的に指定しても害はありません。 REORGANIZE
を繰り返し実行して、すべての未使用スペースの回収を完了する必要がある場合があります。
残念ながら、LOBデータの編成方法とLOB圧縮の実装方法は、何回実行しても、この方法で未使用の領域をすべて再利用できるとは限らないことを意味します。非常に遅くなることもあります。
また、関連するQ&Aでメソッドを試すこともできます 未使用のスペースSQL Serverテーブルの解放
何らかの理由で上記がうまくいかない場合は、exportデータをファイルに保存し、truncateテーブル、次にreloadテーブル。これを実現する方法はいくつかあります。たとえば bcpユーティリティ などです。
次の例では、幅が10,000行のテーブルを作成します。
_CREATE TABLE dbo.Test
(
c1 bigint IDENTITY NOT NULL,
c2 nvarchar(max) NOT NULL,
CONSTRAINT PK_dbo_Test
PRIMARY KEY CLUSTERED (c1)
);
-- Load 10,000 wide rows
INSERT dbo.Test WITH (TABLOCKX)
(c2)
SELECT TOP (10000)
REPLICATE(CONVERT(nvarchar(max), 'X'), 50000)
FROM master.sys.columns AS C1
CROSS JOIN master.sys.columns AS C2;
_
_sys.dm_db_index_physical_stats
_ DMVを使用してスペース使用量を確認できます。
_SELECT
DDIPS.index_id,
DDIPS.partition_number,
DDIPS.index_type_desc,
DDIPS.index_depth,
DDIPS.index_level,
DDIPS.page_count,
DDIPS.avg_page_space_used_in_percent
FROM sys.dm_db_index_physical_stats
(
DB_ID(),
OBJECT_ID(N'dbo.Test', N'U'),
1,
NULL,
'DETAILED'
) AS DDIPS
WHERE
DDIPS.alloc_unit_type_desc = N'LOB_DATA';
_
次に、LOBコンテンツをより小さいサイズに更新します(ただし、行外ストレージを必要とするものです)。
_-- Change LOB data to a smaller value (that will not move in-row)
UPDATE dbo.Test WITH (TABLOCKX)
SET c2 = REPLICATE(CONVERT(nvarchar(max), 'Y'), 5000);
_
一部のスペースが再利用されましたが、残りのページは、実際よりもいっぱいになっていることに注意してください。
以下を使用してLOBスペースを圧縮できます。
_ALTER INDEX PK_dbo_Test ON dbo.Test
REORGANIZE
WITH (LOB_COMPACTION = ON);
_
これにより、圧縮とスペースの節約になりますが、完全ではありません。圧縮を再度実行すると、状況が改善される場合と改善されない場合があります。私のテストでは、何回再実行しても、テストは行われませんでした。
これをManagement Studioから完全に行う1つの方法は、_xp_cmdshell
_を使用してテーブルデータをファイルにエクスポートすることです。 _xp_cmdshell
_が現在有効になっていない場合は、次のようにします。
_-- Enable xp_cmdshell if necessary
EXECUTE sys.sp_configure
@configname = 'show advanced options',
@configvalue = 1;
RECONFIGURE;
EXECUTE sys.sp_configure
@configname = 'xp_cmdshell',
@configvalue = 1;
RECONFIGURE;
_
これでエクスポートを実行できます:
_-- Export table
EXECUTE sys.xp_cmdshell
'bcp Sandpit.dbo.Test out c:\temp\Test.bcp -n -S .\SQL2017 -T';
_
パスと_-S
_サーバー名を変更し、場合によってはログイン認証情報を提供する必要があることに注意してください。
テーブルをトランケートし、_BULK INSERT
_を使用してリロードする方法:
_-- Truncate
TRUNCATE TABLE dbo.Test;
-- Switch to BULK_LOGGED recovery model if currently set to FULL
-- Bulk load
BULK INSERT dbo.Test
FROM 'c:\temp\Test.bcp'
WITH
(
DATAFILETYPE = 'widenative',
ORDER (c1),
TABLOCK,
KEEPIDENTITY
);
_
最後のステップは、アイデンティティシードをリセットすることです。
_-- Check and reseed identity
DBCC CHECKIDENT('dbo.Test', RESEED);
_
この一連の操作は、通常、LOB圧縮よりも高速であり、常に最適な結果を生成します。
上記は、長期にわたるバグが原因である可能性があるため、それほど効率的ではありません。 IDENTITY列を使用したBULK INSERTは、SORTを使用したクエリプランを作成します 。そこに記載されている回避策は効果的ですが、テーブルが非常に大きい場合にのみ問題が発生します。
エクスポートされたデータを保持するために使用される一時ファイルを削除することを忘れないでください。
もちろん、最も便利な一括エクスポート/インポートアプローチを自由に使用できます。 _xp_cmdshell
_またはbcp
を使用する必要はありません。
その他の注意事項:
FILLFACTOR
はindex pagesにのみ適用されます。行外のLOBストレージ(インデックスページに格納されない)には影響しません。別の方法として、SQL Server 2016から利用可能な COMPRESS
および DECOMPRESS
関数を使用して、データを明示的に圧縮および解凍できます。
COMPRESS
およびDECOMPRESS
組み込み関数によって提供されるのと同じ圧縮機能を取得するためにSQL Server 2014(ここではこの場合)またはそれ以前(SQL Server 2005まで)を使用する場合のオプションは、SQLCLRを使用することです。これだけを実行するビルド済みの関数は、 Solomon Rutzky によって記述された無料バージョンの SQL# で使用できます。 Util_GZipおよびUtil_GUnzip関数は、それぞれCOMPRESS
およびDECOMPRESS
と同等である必要があります。また、SQL Server 2012以降を使用している場合は、SQL Serverを実行しているサーバーを.NET Frameworkバージョン4.5以降で更新し、大幅に改善された圧縮アルゴリズムが使用されるようにする必要があります。
SQL Server Express 2016 SP1以降にアップグレードできる場合は、 DATA COMPRESSION を使用することにより、大幅にスペースを節約できます。
データベースが肥大化している他の要素があるかもしれませんが、Dan Guzmanのコメントが示唆しているように、すべてのインデックスのFILL FACTORを確認する必要があります。
0(ゼロ)または100以外の値は、インデックスが作成(または再構築)されたときに、SQL Serverが各ページをFILL FACTORのパーセンテージまでしか満たさなかったことを意味します。したがって、たとえば、FILL FACTORが50の場合、インデックスの作成/再構築中にページの50%のみが埋められ、実際にデータを保持するために必要なスペースの量は基本的に2倍になります。
投稿からクエリを取得する SQL ServerデータベースのインデックスのFILL FACTORを検索する
SQL Serverデータベース内の0または100以外のFILL FACTORを持つすべてのユーザーテーブルのすべてのインデックスを検索する場合:
SELECT DB_NAME() AS Database_Name
, sc.name AS Schema_Name
, o.name AS Table_Name
, o.type_desc
, i.name AS Index_Name
, i.type_desc AS Index_Type
, i.fill_factor
FROM sys.indexes i
INNER JOIN sys.objects o ON i.object_id = o.object_id
INNER JOIN sys.schemas sc ON o.schema_id = sc.schema_id
WHERE i.name IS NOT NULL
AND o.type = 'U'
AND i.fill_factor not in (0, 100)
ORDER BY i.fill_factor DESC, o.name
曲線因子に関連する追加の有益な情報は、次の場所にあります。