Leituras lógicas diferentes ao acessar os mesmos dados LOB

26

Aqui estão três testes simples que lêem os mesmos dados, mas relatam leituras lógicas muito diferentes:

Configuração

O script a seguir cria uma tabela de teste com 100 linhas idênticas, cada uma contendo uma coluna xml com dados suficientes para garantir que ela seja armazenada fora da linha. No meu banco de dados de teste, o comprimento do xml gerado é 20.204 bytes para cada linha.

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

Testes

Os três testes a seguir leem a coluna xml com:

  1. Uma SELECTdeclaração clara
  2. Atribuindo o xml a uma variável
  3. Usando SELECT INTOpara criar uma tabela temporária
-- 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;

Resultados

A saída é:

=== Simples SELECT ====
Tabela 'XMLTest'. Contagem de digitalizações 1, leituras lógicas 3, leituras físicas 1, leituras antecipadas 0,
    lob lógico lê 795, lob físico lê 37, lob read-ahead lê 796.

=== Atribuir a uma variável ====
Tabela 'XMLTest'. Contagem de digitalizações 1, leituras lógicas 3, leituras físicas 1, leituras antecipadas 0,
    lob lógico lê 0, lob físico lê 0, lob read-ahead lê 0.

=== SELECIONAR EM ====
Tabela 'XMLTest'. Contagem de digitalizações 1, leituras lógicas 3, leituras físicas 1, leituras antecipadas 0,
    lob lê 300, lógico lê 37, lob lê 400.

Questões

  • Por que as leituras LOB são tão diferentes?
  • Certamente os mesmos dados foram lidos em cada teste?
Paul White diz que a GoFundMonica
fonte

Respostas:

27

Nem todas as leituras são iguais. O SQL Server sabe que acessar dados LOB é caro e tenta evitá-los quando possível. Também existem diferenças detalhadas na maneira como os dados LOB são lidos em cada caso:

Sumário

Os números são diferentes porque:

  • O select lê o LOB em blocos do tamanho de pacotes
  • O teste de atribuição de variáveis não lê o LOB
  • O teste "selecionar em" lê o LOB em páginas inteiras

Detalhe

  1. Avião SELECT

    Selecione o plano

    A Verificação de Índice em Cluster não lê nenhum dado LOB. Ele atribui apenas um identificador LOB do mecanismo de armazenamento . O identificador não é usado até que o controle retorne à raiz do plano.

    O conteúdo LOB da linha atual é lido em pedaços do tamanho de pacote TDS e transmitido para o cliente. As leituras lógicas contam o número de vezes que uma página é tocada, portanto:

    O número de leituras relatadas é igual ao número de leituras em blocos executadas, mais uma por cada vez que ocorre uma transição de página LOB.

    Por exemplo: Uma leitura lógica é contada no início de cada bloco, à medida que o processo toca a página correspondente à posição atual do fluxo. Onde os pacotes são menores que uma página de banco de dados (o caso usual), várias leituras lógicas são contadas para a mesma página. Se o tamanho do pacote fosse tão grande que o LOB inteiro pudesse caber em um pedaço, o número de leituras lógicas relatadas seria o número de páginas do LOB.

  2. Atribuição variável

    Plano variável

    A Verificação de Índice em Cluster atribui um identificador de LOB como antes. Na raiz do plano, o identificador LOB é copiado para a variável. Os dados LOB em si nunca são acessados ​​(zero leituras LOB), porque a variável nunca é lida. Mesmo se fosse, seria apenas através do identificador LOB atribuído pela última vez.

    Não há leituras de LOB porque os dados LOB nunca são acessados.

  3. SELECT INTO

    Selecionar no plano

    Este plano usa o provedor de conjunto de linhas em massa para copiar os dados LOB da tabela de origem para a nova tabela. Ele processa uma página LOB completa em cada leitura (sem streaming ou chunking).

    O número de leituras lógicas corresponde ao número de páginas LOB na tabela de teste.

Paul White diz que a GoFundMonica
fonte