web-dev-qa-db-ja.com

クラスター化列ストアインデックスのスペース使用

クラスター化された列ストアインデックスを持つ単純なテーブルがあります。

ID INT NOT NULL,
Hash BINARY(20) NOT NULL

このテーブルには数十億行があり、sp_spaceusedsys.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未満であると述べています。

6
kirchner

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');

結果:

AU/partition query

計算しなかった未使用以外は、結果はsp_spaceusedと一致します。

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');

結果:

dm_db_partition_stats

これについておっしゃっていましたが、sp_spaceusedallocation_unitsは、ページがどの程度いっぱいか空であるかに関係なく、ページ数を反映していることを明示的に伝えたかっただけです。行グループDMVは、実際のデータのみを反映しています。 ドキュメントの状態 (私の強調):

すべてのバイト単位のサイズデータこの行グループ内(メタデータまたは共有ディクショナリを含まない)

一方、 sys.dm_db_partition_stats は、データではなくページ全体を明示的に示しますが、ここでは、各LOBが8Kページであることを指定する必要があると主張します。

パーティションで列ストアインデックスを格納および管理するために使用されるLOBの総数。

どの番号を信頼したいのか、それはあなた次第です。

余談ですが、Niko Neugebauerは、辞書の圧縮されたサイズのみが列ストアDMVで公開されているという事実について話しました here 、そしてそれについて フィードバックアイテム を上げました。列ストアDMVで公開される可能性のある他の情報もあるようです。

3
Aaron Bertrand