クラスター化された列ストアインデックスを持つ単純なテーブルがあります。
ID INT NOT NULL,
Hash BINARY(20) NOT NULL
このテーブルには数十億行があり、sp_spaceused
、sys.allocation_units
、およびSSMSレポートによると、そのサイズは約25GBです。
私の問題は、このスペースのすべてを説明できないことです。 sys.column_store_row_groups
およびsys.column_store_segments
をクエリすると、約7,8GBしか得られません。インデックスはディクショナリを使用しません。primary_dictionary_id
およびsecondary_dictionary_id
は、すべてのセグメントで-1です。 sys.column_store_dictionaries
をクエリすると、行はまったく返されません。
タプルムーバーはその仕事を終え、すべての行グループは圧縮された状態にあります。念のため、すでにALTER INDEX REORGANIZE
を試しました。
サイズの違いについての私の唯一の考えは、私が説明していないいくつかの辞書のようなものです。何が欠けているのかについてのアイデアはありますか?
SQL Server 2017(RTM-CU4)を実行しています。
編集1:
これは、問題のテーブルのsp_spaceusedからの出力です。
+--------+------------+-------------+-------------+------------+----------+
| name | rows | reserved | data | index_size | unused |
+--------+------------+-------------+-------------+------------+----------+
| IdsBin | 1073741824 | 25028112 KB | 25007432 KB | 16 KB | 20664 KB |
+--------+------------+-------------+-------------+------------+----------+
編集2:
これは100万行の再現スクリプトです。私のマシンでは約1分で実行されます。 warning:新しいデータベースを削除して再作成します
USE master;
GO
DROP DATABASE IF EXISTS MyDbWeirdTest;
GO
CREATE DATABASE MyDbWeirdTest;
GO
USE MyDbWeirdTest;
GO
CREATE TABLE IdsBin (
ID INT NOT NULL,
Hash BINARY(20) NOT NULL
);
CREATE CLUSTERED COLUMNSTORE INDEX ix1 ON IdsBin
GO
CREATE TYPE tBin AS TABLE (
ID INT,
Hash BINARY(20)
);
GO
CREATE OR ALTER PROCEDURE pBin (
@ids AS dbo.tBin READONLY
)
AS
BEGIN
SET NOCOUNT ON;
INSERT dbo.IdsBin
SELECT ID, Hash FROM @ids;
END;
GO
SET NOCOUNT ON;
DECLARE @i INT = 1, @t INT = 1;
DECLARE @tvp dbo.tBin;
WHILE @t <= 1000000
BEGIN
DELETE @tvp;
BEGIN TRAN;
WHILE @i <= 1000
BEGIN
INSERT @tvp VALUES (@t, HASHBYTES('SHA1', CAST(@t AS BINARY(4))));
SET @i = @i + 1;
SET @t = @t + 1;
END;
EXEC pBin @tvp;
COMMIT;
SET @i = 1;
END;
GO
ALTER INDEX ix1 on IdsBin REBUILD;
GO
この再現では、sp_spaceusedは以下を示します。
+--------+----------------------+----------+----------+------------+--------+
| name | rows | reserved | data | index_size | unused |
+--------+----------------------+----------+----------+------------+--------+
| IdsBin | 1000000 | 22728 KB | 22640 KB | 0 KB | 88 KB |
+--------+----------------------+----------+----------+------------+--------+
sys.column_store_row_groups:
+-----------+----------+------------------+--------------+---------------------+-------+-------------------+------------+--------------+---------------+
| object_id | index_id | partition_number | row_group_id | delta_store_hobt_id | state | state_description | total_rows | deleted_rows | size_in_bytes |
+-----------+----------+------------------+--------------+---------------------+-------+-------------------+------------+--------------+---------------+
| 901578250 | 1 | 1 | 0 | NULL | 3 | COMPRESSED | 1000000 | 0 | 5896938 |
+-----------+----------+------------------+--------------+---------------------+-------+-------------------+------------+--------------+---------------+
したがって、sp_spaceusedは約22MBを与え、sys.allocation_units(表示されていません)は同意します。しかし、どの列ストアDMVもその数に同意していないようで、インデックスのサイズが6MB未満であると述べています。
ColumnStoreデータに関するメタデータ情報のsys.column_store_segments
およびsys.column_store_row_groups
ストアsomeが、圧縮されたを表すことになると思いますサイズ。同様に割り当てられているLOB構造があり、アロケーションユニット/パーティションDMVで非圧縮サイズを確認できます(そして、DBCC PAGE
を使用してページに到達した場合、それらは比較的大きいことがわかります。空の)。言い換えると、sys.column_store_row_groups
は、これらのページに保存されているデータの量を示しますが、それらのページの空き領域は追加しません(フラグメント化されたインデックスのように、データファイルとメモリの領域を占有します)。または、非常に低いFILL FACTORを持つインデックス)。
私はあなたの再現を実行しました、そしてここに私が見たものがあります:
SELECT
a.[type_desc],
p.[rows],
a.total_pages, reserved_kb = a.total_pages * 8,
a.used_pages, data_kb = a.used_pages * 8
FROM sys.allocation_units AS a
INNER JOIN sys.partitions AS p
ON a.container_id = p.[partition_id]
WHERE p.[object_id] = OBJECT_ID(N'dbo.IdsBin');
結果:
計算しなかった未使用以外は、結果はsp_spaceused
と一致します。
また、これらの番号はsys.dm_db_partition_stats
でも確認できます。
SELECT
lob_reserved_page_count, reserved_kb = lob_reserved_page_count * 8,
lob_used_page_count, data_kb = lob_used_page_count * 8
FROM sys.dm_db_partition_stats
WHERE [object_id] = OBJECT_ID(N'dbo.IdsBin');
結果:
これについておっしゃっていましたが、sp_spaceused
とallocation_units
は、ページがどの程度いっぱいか空であるかに関係なく、ページ数を反映していることを明示的に伝えたかっただけです。行グループDMVは、実際のデータのみを反映しています。 ドキュメントの状態 (私の強調):
すべてのバイト単位のサイズデータこの行グループ内(メタデータまたは共有ディクショナリを含まない)
一方、 sys.dm_db_partition_stats
は、データではなくページ全体を明示的に示しますが、ここでは、各LOBが8Kページであることを指定する必要があると主張します。
パーティションで列ストアインデックスを格納および管理するために使用されるLOBの総数。
どの番号を信頼したいのか、それはあなた次第です。
余談ですが、Niko Neugebauerは、辞書の圧縮されたサイズのみが列ストアDMVで公開されているという事実について話しました here 、そしてそれについて フィードバックアイテム を上げました。列ストアDMVで公開される可能性のある他の情報もあるようです。