如果索引中包含 VARCHAR(MAX) 列,是否始终将整个值存储在索引页中?

mus*_*cio 14 sql-server varchar

我是出于好奇而问这个问题的,受到这个问题的启发。

我们知道VARCHAR(MAX)值超过8000个字节并不存储在行,但在不同的LOB页。随后检索具有此类值的行需要两个或多个逻辑 IO 操作(实际上,理论上需要多一个)。

我们可以将一VARCHAR(MAX)列作为INCLUDEd添加到唯一索引,如链接问题所示。如果此列的值长度超过 8000 字节,这些值是否仍会“内联”存储在索引叶页中,还是也将移动到 LOB 页?

Joe*_*ish 19

超过 8000 字节的值不能“内联”存储。它们存储在 LOB 页上。您可以通过sys.dm_db_index_physical_stats看到这一点。从一个简单的表开始:

USE tempdb;

DROP TABLE IF EXISTS #LOB_FOR_ME;

CREATE TABLE #LOB_FOR_ME (
ID BIGINT,
MAX_VERNON_WAS_HERE VARCHAR(MAX) 
);

CREATE INDEX IX ON #LOB_FOR_ME (ID) INCLUDE (MAX_VERNON_WAS_HERE);
Run Code Online (Sandbox Code Playgroud)

现在插入一些行的值占用 8000 字节的VARCHAR(MAX)列并检查 DMF:

USE tempdb;

INSERT INTO #LOB_FOR_ME
SELECT 1, REPLICATE('Z', 8000)
FROM master..spt_values;

SELECT index_level, index_type_desc, alloc_unit_type_desc, page_count, record_count
FROM sys.dm_db_index_physical_stats(DB_ID(), OBJECT_ID('#LOB_FOR_ME'), 2, NULL , 'DETAILED'); 
Run Code Online (Sandbox Code Playgroud)

索引中没有 LOB 页:

???????????????????????????????????????????????????????????????????????????????????????
? index_level ?  index_type_desc   ? alloc_unit_type_desc ? page_count ? record_count ?
???????????????????????????????????????????????????????????????????????????????????????
?           0 ? NONCLUSTERED INDEX ? IN_ROW_DATA          ?       2540 ?         2540 ?
?           1 ? NONCLUSTERED INDEX ? IN_ROW_DATA          ?         18 ?         2540 ?
?           2 ? NONCLUSTERED INDEX ? IN_ROW_DATA          ?          1 ?           18 ?
???????????????????????????????????????????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

但是,如果我添加具有 8001 个字节的值的行:

USE tempdb;

INSERT INTO #LOB_FOR_ME
SELECT 2, REPLICATE(CAST('Z' AS VARCHAR(MAX)), 8001)
FROM master..spt_values;

SELECT index_level, index_type_desc, alloc_unit_type_desc, page_count, record_count
FROM sys.dm_db_index_physical_stats(DB_ID(), OBJECT_ID('#LOB_FOR_ME'), 2, NULL , 'DETAILED'); 
Run Code Online (Sandbox Code Playgroud)

现在,我刚插入的每一行的索引中都有 1 个 LOB 页面:

???????????????????????????????????????????????????????????????????????????????????????
? index_level ?  index_type_desc   ? alloc_unit_type_desc ? page_count ? record_count ?
???????????????????????????????????????????????????????????????????????????????????????
?           0 ? NONCLUSTERED INDEX ? IN_ROW_DATA          ?       2556 ?         5080 ?
?           1 ? NONCLUSTERED INDEX ? IN_ROW_DATA          ?         18 ?         2556 ?
?           2 ? NONCLUSTERED INDEX ? IN_ROW_DATA          ?          1 ?           18 ?
?           0 ? NONCLUSTERED INDEX ? LOB_DATA             ?       2540 ?         2540 ?
???????????????????????????????????????????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

您还可以SET STATISTICS IO ON;通过正确的查询看到这一点。考虑以下仅查看 8000 字节行的查询:

SELECT SUM(LEN(MAX_VERNON_WAS_HERE))
FROM #LOB_FOR_ME
WHERE ID = 1;
Run Code Online (Sandbox Code Playgroud)

执行结果:

扫描计数1,逻辑读2560,物理读0,预读0,lob逻辑读0,lob物理读0,lob预读0。

如果我改为查询 8001 字节的行:

SELECT SUM(LEN(MAX_VERNON_WAS_HERE))
FROM #LOB_FOR_ME
WHERE ID = 2;
Run Code Online (Sandbox Code Playgroud)

现在我看到 lob 写着:

扫描计数 1,逻辑读 20,物理读 0,预读 0,lob 逻辑读 5080,lob 物理读 0,lob 预读 0。


归档时间:

查看次数:

3545 次

最近记录:

6 年,3 月 前