SQL Serverは重複する行を格納する代わりにポインターを使用しますか?


8

sp_spaceusedソフトウェアで操作を実行する前後に、組み込みのストアドプロシージャを使用して、どのテーブルに行が挿入されているか、および各テーブルのサイズがどのように変化するかを確認しています。

私が目にしているのは、行が書き込まれるすべてのテーブルのうち、テーブルが横に増えていることを示すのはほんの一握りです。行が追加されたことを示す他のものは、このストアドプロシージャからのサイズの変化を示していません。

これが当てはまらない唯一のケースは、すべてのテーブルで切り捨てを実行した後の最初のトランザクションです。つまり、重複したデータを保存する代わりに、SQL Serverは行が挿入されていることを示していますが、以前の同一の行へのポインタを保存しているだけのようです。

誰でもこれを確認できますか?


dba.seのフラグ付き
gbn

回答:


13

いいえ、SQL Serverは重複行を検出しません

SQL Serverは、割り当てられたページ内の空または部分的に空のページを埋めています。

したがって、非常に狭い行(2列と表示されている)がある場合、使用するスペースを増やすことなく、同じページに数百行を追加できます。

簡単なデモ(重複する行はありませんが、必要に応じてこれで遊ぶことができます)

IF OBJECT_ID('dbo.Demo') IS NOT NULL
    DROP TABLE dbo.Demo;
GO
CREATE TABLE dbo.Demo (DemoID int NOT NULL IDENTITY(1,1), Demo char(1) NOT NULL)
GO
SELECT 'zero rows, zero space', SUM(ps.reserved_page_count)/128.0 AS ReservedMB, SUM(ps.used_page_count)/128.0 AS UsedMB
FROM sys.dm_db_partition_stats ps
WHERE ps.object_id = OBJECT_ID('dbo.Demo')
GO

INSERT dbo.Demo VALUES ('a');
GO
SELECT 'one row. Peanuts', SUM(ps.reserved_page_count)/128.0 AS ReservedMB, SUM(ps.used_page_count)/128.0 AS UsedMB
FROM sys.dm_db_partition_stats ps
WHERE ps.object_id = OBJECT_ID('dbo.Demo')
GO

INSERT dbo.Demo VALUES ('b');
GO 100
SELECT '101 rows. All on one page', SUM(ps.reserved_page_count)/128.0 AS ReservedMB, SUM(ps.used_page_count)/128.0 AS UsedMB
FROM sys.dm_db_partition_stats ps
WHERE ps.object_id = OBJECT_ID('dbo.Demo')
GO

INSERT dbo.Demo VALUES ('b');
GO 1899
SELECT '2000 rows. More than one page', SUM(ps.reserved_page_count)/128.0 AS ReservedMB, SUM(ps.used_page_count)/128.0 AS UsedMB
FROM sys.dm_db_partition_stats ps
WHERE ps.object_id = OBJECT_ID('dbo.Demo')
GO

TRUNCATE TABLE dbo.Demo
GO
SELECT 'zero rows, zero space. TRUNCATE deallocates pages', SUM(ps.reserved_page_count)/128.0 AS ReservedMB, SUM(ps.used_page_count)/128.0 AS UsedMB
FROM sys.dm_db_partition_stats ps
WHERE ps.object_id = OBJECT_ID('dbo.Demo')
GO

INSERT dbo.Demo VALUES ('c');
GO 500
SELECT '500 rows. Some space used', SUM(ps.reserved_page_count)/128.0 AS ReservedMB, SUM(ps.used_page_count)/128.0 AS UsedMB
FROM sys.dm_db_partition_stats ps
WHERE ps.object_id = OBJECT_ID('dbo.Demo')
GO

DELETE dbo.Demo
GO
SELECT 'zero rows after delete. Space still allocated', SUM(ps.reserved_page_count)/128.0 AS ReservedMB, SUM(ps.used_page_count)/128.0 AS UsedMB
FROM sys.dm_db_partition_stats ps
WHERE ps.object_id = OBJECT_ID('dbo.Demo')
GO

IF OBJECT_ID('dbo.Demo') IS NOT NULL
    DROP TABLE dbo.Demo;
GO

ありがとう、そんな素晴らしい答えです。もっと賛成票を投じたいと思います。おそらく、あなたがとても親切だとしたら、ページ内で使用される実際のデータをどのように計算するかを提案することもできます。名前行の予約データindex_size未使用料金6 16 KB 8 KB 8 KB 0 KBこれから、6行に使用しているページの量を確認できません。これは事実ではないことはわかっていますが、このページでは0KBが使用されていないことがわかります。

私はDBCC SHOWCONTIGを試してみましたが、LOBに格納されている大きな列は理解できません。

新しい質問を作成するのではなく、コメントする方がいいと思いました...幅の広いテーブルを格納する方法は?たとえば、本当に幅の広いテーブルがあり、ほとんどの場合60%程度の列がnullである場合はどうなりますか?私はそれらの列があるため、この行は、ページ内の店舗にスペースの同じ量を取ると仮定COULDデータを持っていますか?ストレージのみの観点から(もちろん、文字どおりに解釈することもできます)、幅の狭いテーブルを増やすことをお勧めします。とにかく「空の」列を頻繁にプルする必要がある場合は、メインテーブルと一緒に保持することはおそらく意味がありますか?
bdwakefield 2014年

7

SQL Serverは重複する行を格納する代わりにポインターを使用しますか?

SQL Serverのバージョンとデータ圧縮オプションによって異なります。

  • SQL Server 2008以降、行またはページレベルでの圧縮オプションがあります。
  • ページレベルの圧縮では、圧縮に多くのアルゴリズム/手法が使用されます。あなたの質問(重複データのポインター)に関して、ページ圧縮は(また) 接頭辞圧縮と辞書圧縮を使用します:

プレフィックス圧縮 [...]列内の繰り返されるプレフィックス値は、対応するプレフィックスへの参照で置き換えられます[...]

辞書圧縮プレフィックス圧縮が完了した後、辞書圧縮が適用されます。辞書圧縮は、ページ上の任意の場所で繰り返し値を検索し、CI領域に格納します。接頭辞圧縮とは異なり、辞書圧縮は1つの列に制限されません。辞書圧縮は、ページのどこにでも出現する繰り返し値を置き換えることができます。次の図は、辞書圧縮後の同じページを示しています。

したがって、プレフィックスとディクショナリの圧縮(ページ圧縮)の場合、SQL Serverはポインターを使用して (部分的または完全に)重複した(重複した行ではない)を同じ列またはdiff内に格納します。列。

CREATE DATABASE TestComp;
GO

USE TestComp;
GO

CREATE TABLE Person1 (
    PersonID INT IDENTITY PRIMARY KEY,
    FirstName NVARCHAR(100) NOT NULL,
    LastName NVARCHAR(100) NOT NULL
);
GO

DECLARE 
    @f NVARCHAR(100) = REPLICATE('A',100), 
    @l NVARCHAR(100) = REPLICATE('B',100);

INSERT Person1 (FirstName, LastName)
VALUES (@f, @l);
GO 1000

CREATE TABLE Person2 (
    PersonID INT IDENTITY PRIMARY KEY,
    FirstName NVARCHAR(100) NOT NULL,
    LastName NVARCHAR(100) NOT NULL
);
GO

ALTER TABLE Person2
REBUILD
WITH (DATA_COMPRESSION=PAGE);
GO

DECLARE 
    @f NVARCHAR(100) = REPLICATE('A',100), 
    @l NVARCHAR(100) = REPLICATE('B',100);

INSERT Person2 (FirstName, LastName)
VALUES (@f, @l);
GO 1000

SELECT  f.page_count AS PageCount_Person1_Uncompressed
FROM    sys.dm_db_index_physical_stats(DB_ID(), OBJECT_ID('Person1'), 1, DEFAULT, DEFAULT) f
SELECT  f.page_count AS PageCount_Person2_Compressed
FROM    sys.dm_db_index_physical_stats(DB_ID(), OBJECT_ID('Person2'), 1, DEFAULT, DEFAULT) f
GO

結果:

PageCount_Person1_Uncompressed
------------------------------
53

PageCount_Person2_Compressed
----------------------------
2
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.