AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 86383
Accepted
Paul White
Paul White
Asked: 2014-12-18 02:12:48 +0800 CST2014-12-18 02:12:48 +0800 CST 2014-12-18 02:12:48 +0800 CST

Concessão excessiva de memória de classificação

  • 772

Por que essa consulta simples recebe tanta memória?

-- Demo table
CREATE TABLE dbo.Test
(
    TID integer IDENTITY NOT NULL,
    FilterMe integer NOT NULL,
    SortMe integer NOT NULL,
    Unused nvarchar(max) NULL,

    CONSTRAINT PK_dbo_Test_TID
    PRIMARY KEY CLUSTERED (TID)
);
GO
-- 100,000 example rows
INSERT dbo.Test WITH (TABLOCKX)
    (FilterMe, SortMe)
SELECT TOP (100 * 1000)
    CHECKSUM(NEWID()) % 1000,
    CHECKSUM(NEWID())
FROM sys.all_columns AS AC1
CROSS JOIN sys.all_columns AS AC2;
GO    
-- Query
SELECT
    T.TID,
    T.FilterMe,
    T.SortMe,
    T.Unused
FROM dbo.Test AS T 
WHERE 
    T.FilterMe = 567
ORDER BY 
    T.SortMe;

Para cerca de 50 linhas, o otimizador reserva quase 500 MB para a classificação:

Plano estimado

sql-server execution-plan
  • 3 3 respostas
  • 11561 Views

3 respostas

  • Voted
  1. Best Answer
    Paul White
    2014-12-18T02:12:48+08:002014-12-18T02:12:48+08:00

    Este é um bug no SQL Server (de 2008 a 2014 inclusive).

    Meu relatório de bug está aqui .

    A condição de filtragem é enviada para o operador de varredura como um predicado residual, mas a memória concedida para a classificação é calculada erroneamente com base na estimativa de cardinalidade pré-filtro .

    Para ilustrar o problema, podemos usar o sinalizador de rastreamento 9130 (não documentado e sem suporte) para impedir que o filtro seja enviado para baixo no operador de digitalização. A memória concedida para a classificação agora é baseada corretamente na cardinalidade estimada da saída do filtro, não na varredura:

    SELECT
        T.TID,
        T.FilterMe,
        T.SortMe,
        T.Unused
    FROM dbo.Test AS T 
    WHERE 
        T.FilterMe = 567
    ORDER BY 
        T.SortMe
    OPTION (QUERYTRACEON 9130); -- Not for production systems!
    

    Plano estimado

    Para um sistema de produção , será necessário tomar medidas para evitar a forma de plano problemática (um filtro inserido em uma varredura com uma classificação em outra coluna). Uma maneira de fazer isso é fornecer um índice sobre a condição do filtro e/ou fornecer a ordem de classificação necessária.

    -- Index on the filter condition only
    CREATE NONCLUSTERED INDEX IX_dbo_Test_FilterMe
    ON dbo.Test (FilterMe);
    

    Com esse índice instalado, a concessão de memória desejada para a classificação é de apenas 928 KB :

    Com índice de filtro

    Indo além, o seguinte índice pode evitar completamente a classificação ( zero concessão de memória):

    -- Provides filtering and sort order
    -- nvarchar(max) column deliberately not INCLUDEd
    CREATE NONCLUSTERED INDEX IX_dbo_Test_FilterMe_SortMe
    ON dbo.Test (FilterMe, SortMe);
    

    Com filtro e índice de classificação

    Testado e com bug confirmado nas seguintes compilações do SQL Server x64 Developer Edition:

    2014   : 12.00.2430 (RTM CU4)
    2012   : 11.00.5556 (SP2 CU3)
    2008R2 : 10.50.6000 (SP3)
    2008   : 10.00.6000 (SP4)
    

    Isso foi corrigido no SQL Server 2016 Service Pack 1 . As notas de versão incluem o seguinte:

    VSTS bug número 8024987 As
    varreduras de tabela e as varreduras de índice com predicado push down tendem a superestimar a concessão de memória para o operador pai.

    Testado e confirmado corrigido em:

    • Microsoft SQL Server 2016 (SP1) - 13.0.4001.0 (X64) Developer Edition
    • Microsoft SQL Server 2014 (SP2-CU3) 12.0.5538.0 (X64) Developer Edition

    Ambos os modelos CE.

    • 42
  2. wBob
    2014-12-19T07:15:37+08:002014-12-19T07:15:37+08:00

    Do SQL 2012 em diante, você pode procurar uma grande discrepância entre SerialRequiredMemorye SerialDesiredMemory, por exemplo, algo assim:

    -- Search plan cache for Memory Grant issues
    IF OBJECT_ID('tempdb..#tmp') IS NOT NULL DROP TABLE #tmp
    
    -- Collect more info about the plan here if required, eg usecounts, objtype etc, 
    SELECT IDENTITY( INT, 1, 1 ) rowId, query_plan
    INTO #tmp
    FROM sys.dm_exec_cached_plans cp WITH(NOLOCK)
        CROSS APPLY sys.dm_exec_query_plan(plan_handle)
    GO
    
    
    ;WITH cte AS
    (
    SELECT
        rowId,
        query_plan,
        m.c.value ('@SerialRequiredMemory', 'INT' ) AS SerialRequiredMemory,
        m.c.value ('@SerialDesiredMemory', 'INT' ) AS SerialDesiredMemory
    
    FROM #tmp t
        CROSS APPLY t.query_plan.nodes ( '//*:MemoryGrantInfo[@SerialDesiredMemory[. > 0]]' ) m(c)
    ), cte2 AS (
    SELECT *,
        CAST( CAST( SerialDesiredMemory AS DECIMAL(10,2) ) / CAST( SerialRequiredMemory AS DECIMAL(10,2) ) AS DECIMAL(10,2) ) Desired_to_Required_ratio
    FROM cte
    )
    SELECT TOP 20
        rowId,
        query_plan,
        SerialRequiredMemory SerialRequiredMemory_KB,
        SerialDesiredMemory SerialDesiredMemory_KB,
        CAST( SerialRequiredMemory / 1024. AS DECIMAL(10,2) ) SerialRequiredMemory_MB,
        CAST( SerialDesiredMemory / 1024. AS DECIMAL(10,2) ) SerialDesiredMemory_MB,
        Desired_to_Required_ratio
    FROM cte2
    WHERE Desired_to_Required_ratio > 100
    ORDER BY Desired_to_Required_ratio DESC
    

    Algumas notas adicionais sobre esses novos atributos aqui . Esta consulta é um pouco grosseira e pronta, mas pegou a consulta de classificação excessiva da minha caixa de desenvolvimento do SQL Server 2014 com uma proporção de 975,47, além de alguns outros planos impressionantes. A proporção 'normal' (pelo menos em meus testes limitados) parece ser ~ 1.

    HTH

    • 5
  3. Doug B
    2015-06-16T09:02:14+08:002015-06-16T09:02:14+08:00

    Obrigado por toda a ajuda. Pensei em enviar uma versão atualizada da consulta acima que consideramos útil.

    -- Search plan cache for Memory Grant issues
    IF OBJECT_ID('tempdb..#tmp') IS NOT NULL DROP TABLE #tmp
    
    -- Collect more info about the plan here if required, eg usecounts, objtype etc, 
    SELECT IDENTITY( INT, 1, 1 ) rowId, query_plan, db = DB_NAME(CAST(pa.value AS int))
    INTO #tmp
    FROM sys.dm_exec_cached_plans cp WITH(NOLOCK)
        CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle)
        OUTER APPLY sys.dm_exec_plan_attributes(cp.plan_handle) pa 
        WHERE pa.attribute = 'dbid' 
    GO
    
    ;WITH cte AS
    (
    SELECT
        rowId,
        query_plan,
        m.c.value ('@SerialRequiredMemory', 'INT' ) AS SerialRequiredMemory,
        m.c.value ('@SerialDesiredMemory', 'INT' ) AS SerialDesiredMemory,
        db
    FROM #tmp t
        CROSS APPLY t.query_plan.nodes ( '//*:MemoryGrantInfo[@SerialDesiredMemory[. > 0]]' ) m(c)
    ), cte2 AS (
    SELECT *,
        CAST( CAST( SerialDesiredMemory AS DECIMAL(10,2) ) / CAST( SerialRequiredMemory AS DECIMAL(10,2) ) AS DECIMAL(10,2) ) Desired_to_Required_ratio
    FROM cte
    )
    SELECT TOP 20
        rowId,
        query_plan,
        SerialRequiredMemory SerialRequiredMemory_KB,
        SerialDesiredMemory SerialDesiredMemory_KB,
        CAST( SerialRequiredMemory / 1024. AS DECIMAL(10,2) ) SerialRequiredMemory_MB,
        CAST( SerialDesiredMemory / 1024. AS DECIMAL(10,2) ) SerialDesiredMemory_MB,
        Desired_to_Required_ratio,
        db
    FROM cte2
    WHERE Desired_to_Required_ratio > 100
    ORDER BY Desired_to_Required_ratio DESC
    
    • 3

relate perguntas

  • SQL Server - Como as páginas de dados são armazenadas ao usar um índice clusterizado

  • Preciso de índices separados para cada tipo de consulta ou um índice de várias colunas funcionará?

  • Quando devo usar uma restrição exclusiva em vez de um índice exclusivo?

  • Quais são as principais causas de deadlocks e podem ser evitadas?

  • Como determinar se um Índice é necessário ou necessário

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve