Логические чтения для поиска по неуникальному кластерному индексу - PullRequest
6 голосов
/ 05 мая 2011

Для определения таблицы

CREATE  TABLE Accounts
(
AccountID INT ,
Filler CHAR(1000)
)

Содержит 21 строку (7 для каждого из значений AccountId 4,6,7).

Имеет 1 корневую страницу и 4 конечных страницы

index_depth page_count           index_level
----------- -------------------- -----------
2           4                    0
2           1                    1

Корневая страница выглядит как

FileId      PageId      ROW         LEVEL       ChildFieldId ChildPageId AccountId (KEY) UNIQUIFIER (KEY) KeyHashValue
----------- ----------- ----------- ----------- ------------ ----------- --------------- ---------------- ------------------------------
1           121         0           1           1            119         NULL            NULL             NULL
1           121         1           1           1            151         6               0                NULL
1           121         2           1           1            175         6               3                NULL
1           121         3           1           1            215         7               1                NULL

Фактическое распределение AccountId записей по этим страницам

AccountID   page_id     Num
----------- ----------- -----------
4           119         7
6           151         3
6           175         4
7           175         1
7           215         6

Запрос

SELECT AccountID 
FROM Accounts 
WHERE AccountID IN (4,6,7) 

Дает следующую статистику ввода-вывода

Table 'Accounts'. Scan count 3, logical reads 13

Почему?

Я думал, что для каждого поиска он будет искатьна первую страницу, которая потенциально может содержать это значение, а затем (при необходимости) продолжать по связанному списку , пока не обнаружит, что первая строка не равна искомому значению.

Однако это только добавляетдо 10 обращений к странице

4)  Root Page -> Page 119 -> Page 151             (Page 151 Contains a 6 so should stop)
6)  Root Page -> Page 119 -> Page 151 -> Page 175 (Page 175 Contains a 7 so should stop)
7)  Root Page -> Page 175 -> Page 215             (No more pages)      

Так что же означает дополнительные 3?

Полный сценарий для воспроизведения

USE tempdb

SET NOCOUNT ON;

CREATE  TABLE Accounts
(
AccountID INT ,
Filler CHAR(1000)
)

CREATE CLUSTERED INDEX ix ON Accounts(AccountID)


INSERT INTO Accounts(AccountID)
SELECT C
FROM (SELECT 4 UNION ALL SELECT 6 UNION ALL SELECT 7) Vals(C)
CROSS JOIN (SELECT TOP (7) 1 FROM master..spt_values) T(X)

DECLARE @AccountID INT

SET STATISTICS IO ON
SELECT @AccountID=AccountID FROM Accounts WHERE AccountID IN (4,6,7) 
SET STATISTICS IO OFF

SELECT index_depth,page_count,index_level
FROM
sys.dm_db_index_physical_stats (2,OBJECT_ID('Accounts'), DEFAULT,DEFAULT, 'DETAILED')

SELECT AccountID, P.page_id, COUNT(*) AS Num
FROM Accounts
CROSS APPLY sys.fn_PhysLocCracker(%%physloc%%) P
GROUP BY AccountID, P.page_id
ORDER BY AccountID, P.page_id

DECLARE @index_info  TABLE
(PageFID  VARCHAR(10), 
  PagePID VARCHAR(10),   
  IAMFID   TINYINT, 
  IAMPID  INT, 
  ObjectID  INT,
  IndexID  TINYINT,
  PartitionNumber TINYINT,
  PartitionID BIGINT,
  iam_chain_type  VARCHAR(30),    
  PageType  TINYINT, 
  IndexLevel  TINYINT,
  NextPageFID  TINYINT,
  NextPagePID  INT,
  PrevPageFID  TINYINT,
  PrevPagePID INT, 
  PRIMARY KEY (PageFID, PagePID));

INSERT INTO @index_info 
    EXEC ('DBCC IND ( tempdb, Accounts, -1)'  ); 

DECLARE @DynSQL NVARCHAR(MAX) = 'DBCC TRACEON (3604);'
SELECT @DynSQL = @DynSQL + '
DBCC PAGE(tempdb, ' + PageFID + ', ' + PagePID + ', 3); '
FROM @index_info     
WHERE IndexLevel = 1

SET @DynSQL = @DynSQL + '
DBCC TRACEOFF(3604); '

CREATE TABLE #index_l1_info  
(FileId  INT, 
  PageId INT,   
  ROW   INT, 
  LEVEL  INT, 
  ChildFieldId  INT,
  ChildPageId INT,
  [AccountId (KEY)] INT,
  [UNIQUIFIER (KEY)] INT,
  KeyHashValue  VARCHAR(30));

INSERT INTO #index_l1_info  
EXEC(@DynSQL)


SELECT *
FROM #index_l1_info

DROP TABLE #index_l1_info
DROP TABLE Accounts

Ответы [ 2 ]

3 голосов
/ 14 сентября 2011

Просто для предоставления ответа в форме ответа, а не в виде обсуждения в комментариях ...

Дополнительные чтения возникают из-за механизма опережающего чтения.Это сканирует родительские страницы конечного уровня в случае, если необходимо выполнить асинхронный ввод-вывод для переноса страниц конечного уровня в буферный кэш, чтобы они были готовы, когда поиск диапазона достигает их.

Можно использовать флаг трассировки 652, чтобы отключить механизм (для всего сервера) и убедиться, что число операций чтения теперь точно равно 10.

2 голосов
/ 05 мая 2011

Из того, что я вижу из вывода DBCC IND, есть 1 корневая страница (type = 10), 1 ключевая страница (type = 2) и четыре листовых страницы (type = 1), всего 6 страниц.

Таким образом, каждое сканирование идет как root -> key -> leaf -> … -> final leaf, что дает 4 чтения для 4 и 7 и 5 операций чтения для 6, всего 4 + 4 + 5 = 13.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...