Логічне зчитування відрізняється під час доступу до одних і тих же даних LOB


26

Ось три прості тести, які читають однакові дані, але повідомляють про дуже різні логічні зчитування:

Налаштування

Наступний скрипт створює тестову таблицю зі 100 однаковими рядками, кожен з яких містить стовпчик xml з достатньою кількістю даних, щоб забезпечити її збереження поза рядками. У моїй тестовій базі даних довжина генерованого xml становить 20 204 байти для кожного рядка.

-- Conditional drop
IF OBJECT_ID(N'dbo.XMLTest', N'U') IS NOT NULL
    DROP TABLE dbo.XMLTest;
GO
-- Create test table
CREATE TABLE dbo.XMLTest
(
    ID integer IDENTITY PRIMARY KEY,
    X xml NULL
);
GO
-- Add 100 wide xml rows
DECLARE @X xml;

SET @X =
(
    SELECT TOP (100) *
    FROM  sys.columns AS C
    FOR XML 
        PATH ('row'),
        ROOT ('root'),
        TYPE
);

INSERT dbo.XMLTest
    (X)
SELECT TOP (100)
    @X
FROM  sys.columns AS C;

-- Flush dirty buffers
CHECKPOINT;

Тести

У наступних трьох тестах читається стовпець xml :

  1. Просте SELECTтвердження
  2. Присвоєння xml змінній
  3. Використовується SELECT INTOдля створення тимчасової таблиці
-- No row count messages or graphical plan
-- Show I/O statistics
SET NOCOUNT ON;
SET STATISTICS XML OFF;
SET STATISTICS IO ON;
GO
PRINT CHAR(10) + '=== Plain SELECT ===='

DBCC DROPCLEANBUFFERS WITH NO_INFOMSGS;

SELECT XT.X 
FROM dbo.XMLTest AS XT;
GO
PRINT CHAR(10) + '=== Assign to a variable ===='

DBCC DROPCLEANBUFFERS WITH NO_INFOMSGS;

DECLARE @X xml;

SELECT
    @X = XT.X
FROM dbo.XMLTest AS XT;
GO
PRINT CHAR(10) + '=== SELECT INTO ===='

IF OBJECT_ID(N'tempdb..#T', N'U') IS NOT NULL
    DROP TABLE #T;

DBCC DROPCLEANBUFFERS WITH NO_INFOMSGS;

SELECT 
    XT.X
INTO #T
FROM dbo.XMLTest AS XT
GO
SET STATISTICS IO OFF;

Результати

Вихід:

=== Звичайний ВИБІР ====
Таблиця "XMLTest". Кількість сканувань 1, логічне зчитування 3, фізичне зчитування 1, читання вперед - 0,
    Логічне логічне зчитування 795, лоб фізичне зчитування 37, лоб зчитування вперед - 796.

=== Призначення змінної ====
Таблиця "XMLTest". Кількість сканувань 1, логічне зчитування 3, фізичне зчитування 1, читання вперед - 0,
    Логічне зчитування 0, лобічне фізичне зчитування 0, лобічне зчитування вперед - 0.

=== ВИБІР ВІД ====
Таблиця "XMLTest". Кількість сканувань 1, логічне зчитування 3, фізичне зчитування 1, читання вперед - 0,
    Логічне зчитування 300, лобічне фізичне зчитування 37, лоб зчитування вперед - 400.

Запитання

  • Чому LOB читає настільки різні?
  • Напевно в кожному тесті були прочитані такі самі дані?

Відповіді:


27

Не всі читання рівні. SQL Server знає, що доступ до даних LOB є дорогим, і намагається уникати цього, коли це можливо. Існують також детальні відмінності у способі зчитування даних LOB у кожному випадку:

Підсумок

Цифри різні, тому що:

  • Вибір читає LOB в шматках розміру пакетів
  • Тест присвоєння змінної взагалі не читає LOB
  • Тест "вибрати в" читає LOB на цілих сторінках

Деталь

  1. Рівнина SELECT

    Виберіть план

    Кластерне сканування індексів не зчитує жодних даних про LOB. Він призначає лише ручку LOB двигуна зберігання . Ручка не використовується, поки контроль не повернеться до кореня плану.

    Вміст LOB поточного рядка зчитується в шматки розміру пакетів TDS і передається клієнту. Логічні читання підраховують кількість торкань сторінки, так що:

    Кількість повідомлень, що повідомляються, дорівнює кількості виконаних фрагментів читання, плюс одне щоразу, коли відбувається перехід сторінки LOB.

    Наприклад: логічне зчитування рахується на початку кожного фрагменту, коли процес торкається сторінки, що відповідає поточному положенню потоку. Якщо пакети менші, ніж сторінки бази даних (звичайний випадок), за одну і ту ж сторінку зараховується кілька логічних читань. Якщо розмір пакету був настільки великим, що весь LOB міг би вміститися в один шматок, кількість логічних зчитувань, про які повідомлялося, була б кількістю сторінок LOB.

  2. Змінне призначення

    Варіабельний план

    Кластерне сканування індексів призначає ручку LOB, як і раніше. У корені плану ручка LOB копіюється в змінну. Самі дані LOB ніколи не мають доступу (нуль LOB читається), тому що змінна ніколи не читається. Навіть якби це було, це було б лише через останню призначену ручку LOB.

    Немає зчитування LOB, оскільки до даних LOB ніколи не можна отримати доступ.

  3. SELECT INTO

    Виберіть Into Plan

    Цей план використовує постачальник масових наборів рядків для копіювання даних LOB з вихідної таблиці в нову таблицю. Він обробляє повну сторінку LOB на кожному прочитаному (без потокового чи збивання).

    Кількість логічних читань відповідає кількості сторінок LOB у тестовій таблиці.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.