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 / 316876
Accepted
SEarle1986
SEarle1986
Asked: 2022-09-15 03:22:40 +0800 CST2022-09-15 03:22:40 +0800 CST 2022-09-15 03:22:40 +0800 CST

Falha ao forçar o plano do Query Store com o motivo da falha NO_PLAN [duplicado]

  • 772
Essa pergunta já tem resposta aqui :
A força do plano do Query Store falha com NO_PLAN dependendo de onde o operador de filtro está no plano (1 resposta)
Fechado há 5 dias .

Eu tenho uma consulta no repositório de consultas para a qual forcei um plano.

Posso confirmar que o plano é forçado com

SELECT * FROM sys.query_store_plan WHERE is_forced_plan = 1

e o plano aparece nos resultados

No entanto, se eu olhar para a last_force_failure_reason_desccoluna, vejoNO_PLAN

Algumas pesquisas no Google me levaram aos seguintes artigos:

Kendra Little

Deepthi Goguri

que ambos sugerem que a alteração dos índices que são usados ​​pelo plano é a causa do motivo da NO_PLANfalha.

Configurei a sessão de eventos estendidos no segundo artigo:

CREATE EVENT SESSION [Querystoreforcedplanfailures] ON SERVER 

ADD EVENT qds.query_store_plan_forcing_failed
ADD TARGET package0.event_file(SET filename=N'C:\Program Files\Microsoft SQL Server\MSSQL15.MSSQLSERVER\MSSQL\Backup\qserror.xel'),
ADD TARGET package0.ring_buffer
WITH (STARTUP_STATE=OFF)
GO

e posso ver os eventos do plano em questão, que possuem o seguinte texto:

O processador de consulta não pôde produzir o plano de consulta porque a dica USE PLAN contém um plano que não pôde ser verificado como válido para a consulta. Remova ou substitua a dica USE PLAN. Para maior probabilidade de forçar o plano bem-sucedido, verifique se o plano fornecido na dica USE PLAN é gerado automaticamente pelo SQL Server para a mesma consulta

A consulta é executada todas as noites como parte de uma construção de data warehouse onde os comandos DDL são comuns, então decidi configurar uma especificação de Auditoria de Banco de Dados para capturar SCHEMA_OBJECT_CHANGE_GROUPtipos de ação para ver se algum índice estava sendo alterado

USE [master]
GO

CREATE SERVER AUDIT [PlanForceAlters]
TO FILE 
(   FILEPATH = N'P:\Audit\'
    ,MAXSIZE = 0 MB
    ,MAX_ROLLOVER_FILES = 2147483647
    ,RESERVE_DISK_SPACE = OFF
) WITH (QUEUE_DELAY = 1000, ON_FAILURE = CONTINUE, AUDIT_GUID = 'd2b6b090-395f-42f9-a8bb-c0ba742ce30e')
ALTER SERVER AUDIT [PlanForceAlters] WITH (STATE = ON)
GO


USE [MyDatabase]
GO

CREATE DATABASE AUDIT SPECIFICATION [PlanForceAlters]
FOR SERVER AUDIT [PlanForceAlters]
ADD (SCHEMA_OBJECT_CHANGE_GROUP)
WITH (STATE = ON)
GO

Quando eu interrogar os resultados da seguinte forma:

SELECT  o.name,
        a.statement
FROM    sys.fn_get_audit_file ('P:\Audit\PlanForce*',default,default) a
        JOIN sys.objects o
            ON o.object_id = a.object_id
WHERE   o.name IN ('MyTableA','MyTable')

Eu posso ver todas as alterações para as tabelas na cláusula IN (quais são as tabelas que são selecionadas na consulta quem é o plano que estou tentando forçar)

Tudo o que posso ver são quedas e recriações de chaves estrangeiras que são bastante normais para nosso data warehouse. As chaves estrangeiras são recriadas com o mesmo nome que tinham quando foram descartadas. A sequência de eventos é

  1. Existem restrições (não confiáveis)
  2. As restrições são eliminadas
  3. Execuções de consulta
  4. Restrições recriadas (mesmo nome e NOCHECK)

O plano que foi forçado é aquele que foi gerado pelo processador de consultas no ponto 3 acima, então como a sequência de eventos é a mesma todas as noites, eu teria pensado que a mudança de restrições é irrelevante?

Fui mais longe e descobri em quais colunas as chaves estrangeiras que foram descartadas / recriadas estão:

SELECT  o.name,
        a.statement,
        c.name
FROM    sys.fn_get_audit_file ('P:\Audit\PlanForce*',default,default) a
        JOIN sys.objects o
            ON o.object_id = a.object_id
        LEFT JOIN sys.foreign_keys fk
            ON  statement LIKE '%ADD CONSTRAINT%' + fk.name + '%' OR
                statement LIKE '%DROP CONSTRAINT%' + fk.name + '%' OR
                statement LIKE '%ADD  CONSTRAINT%' + fk.name + '%' OR
                statement LIKE '%DROP  CONSTRAINT%' + fk.name + '%'
        LEFT JOIN sys.foreign_key_columns fkc
            ON fk.object_id = fkc.constraint_object_id
        LEFT JOIN sys.all_columns c
            ON c.column_id = fkc.parent_column_id AND
                c.object_id = fkc.parent_object_id
WHERE   o.name IN ('MyTableA','MyTableB')

e nenhum deles são colunas em qualquer um dos índices não clusterizados usados ​​no query_plan

Tentei recriar um exemplo em um banco de dados AdventureWorks2016 em que forço um plano que executa uma busca NCI em uma coluna que possui uma chave estrangeira confiável e, em seguida, observo que o otimizador ainda usa o plano, apesar da chave estrangeira ser descartada e ainda usa quando é recriado não confiável:

/* create our stored proc */
CREATE OR ALTER PROCEDURE sp_SalesbyProduct
    @ProductID INT
AS
SELECT 
  SalesOrderID, 
  OrderQty,
  UnitPrice
FROM Sales.SalesOrderDetail
WHERE ProductID = @ProductID
GO

/* create an index to support the query */
CREATE INDEX IX_SalesOrderDetail_ProductID ON Sales.SalesOrderDetail
(
    ProductId
) 
WITH 
(
    DROP_EXISTING = ON
)

/* add a trusted foreign key on the column IX_SalesOrderDetail_ProductID is on */
ALTER TABLE Sales.SalesOrderDetail ADD CONSTRAINT FK_MyKey FOREIGN KEY (ProductID) REFERENCES Production.Product(ProductId)

/* run the proc and ensure differing plans */
DBCC FREEPROCCACHE
GO
EXEC sp_SalesbyProduct @ProductID = 710 /* seek on IX_SalesOrderDetail_ProductID with key lookup */
GO
DBCC FREEPROCCACHE
GO
EXEC sp_SalesbyProduct @ProductID = 870 /* CI Scan*/
GO

insira a descrição da imagem aqui

/* force the seek / lookup plan */
EXEC sp_query_store_force_plan 222, 224;

/* verify the plan is forced */
SELECT  *
FROM    sys.query_store_plan
WHERE   is_forced_plan = 1

insira a descrição da imagem aqui

/* run the queries again and ensure both use the seek / lookup plan */

DBCC FREEPROCCACHE
GO
EXEC sp_SalesbyProduct @ProductID = 710
GO
DBCC FREEPROCCACHE
GO
EXEC sp_SalesbyProduct @ProductID = 870
GO

insira a descrição da imagem aqui

/* drop the constraint on the column in the index */
ALTER TABLE Sales.SalesOrderDetail DROP CONSTRAINT FK_MyKey 

/* is the plan still forced? */

DBCC FREEPROCCACHE
GO
EXEC sp_SalesbyProduct @ProductID = 710
GO
DBCC FREEPROCCACHE
GO
EXEC sp_SalesbyProduct @ProductID = 870
GO

insira a descrição da imagem aqui

Sim!

/* re-add the FK but make it untrusted */
ALTER TABLE Sales.SalesOrderDetail WITH NOCHECK ADD CONSTRAINT FK_MyKey FOREIGN KEY (ProductID) REFERENCES Production.Product(ProductId)

/* is the plan still forced? */

DBCC FREEPROCCACHE
GO
EXEC sp_SalesbyProduct @ProductID = 710
GO
DBCC FREEPROCCACHE
GO
EXEC sp_SalesbyProduct @ProductID = 870
GO

insira a descrição da imagem aqui

Sim!

O que está causando os NO_PLANerros? Tem algo a ver com a eliminação/criação de restrições de chave estrangeira?

sql-server sql-server-2016
  • 2 2 respostas
  • 91 Views

2 respostas

  • Voted
  1. Best Answer
    Paul White
    2022-09-15T07:01:37+08:002022-09-15T07:01:37+08:00

    Descartar e recriar exatamente a mesma restrição de chave estrangeira não impedirá a imposição do plano QDS.

    A palavra exatamente ali inclui o is_not_trustedestado em sys.foreign_keys. O otimizador de consulta não aplica simplificações com base em um relacionamento de chave estrangeira se a restrição não for confiável.

    Tentar forçar um plano baseado em uma chave estrangeira confiável com uma chave estrangeira não confiável pode produzir o NO_PLANmotivo da falha.

    Da mesma forma, tentar forçar um plano gerado quando a chave estrangeira não era confiável pode falhar quando a chave estrangeira for confiável, se as simplificações forem aplicadas para alterar a forma do plano.

    Isso deve ser improvável no seu caso, já que você diz que descarta e recria as chaves estrangeiras e WITH CHECKé o padrão para uma nova restrição. Ainda assim, é algo que você deve verificar.

    Também é possível que você esteja criando a chave estrangeira com NOCHECK, alterando-a para CHECKstatus. Isso não torna a restrição confiável, a menos que você especifique WITH CHECKtambém.

    Para enfatizar o ponto: Este problema surge quando uma simplificação habilitada pela restrição de chave estrangeira confiável altera o espaço de planos considerado pelo otimizador.

    Um exemplo AdventureWorks :

    -- Force the plan for this query
    SELECT COUNT_BIG(*) 
    FROM Production.Product AS P
    JOIN Production.TransactionHistory AS TH
        ON TH.ProductID = P.ProductID;
    
    -- Set the FK to not trusted
    ALTER TABLE Production.TransactionHistory
        NOCHECK CONSTRAINT FK_TransactionHistory_Product_ProductID;
    
    -- NO_PLAN
    SELECT COUNT_BIG(*) 
    FROM Production.Product AS P
    JOIN Production.TransactionHistory AS TH
        ON TH.ProductID = P.ProductID;
    
    -- Make it trusted again
    ALTER TABLE Production.TransactionHistory
        WITH CHECK
            CHECK CONSTRAINT FK_TransactionHistory_Product_ProductID;
    
    -- Plan forced successfully
    SELECT COUNT_BIG(*) 
    FROM Production.Product AS P
    JOIN Production.TransactionHistory AS TH
        ON TH.ProductID = P.ProductID;
    

    Com uma chave estrangeira confiável, o plano é:

    Plano de chave estrangeira confiável

    Quando a restrição não é confiável:

    Plano de chave estrangeira não confiável

    Além disso, você deve começar verificando se o plano no QDS pode ser forçado para esta consulta. Um teste é usar o plano xml de forma USE HINTmanual. Este não é um teste 100% preciso, pois os dois mecanismos são bastante diferentes, mas pode ajudar.

    Not all plans stored in QDS are capable of being forced. For complex queries, the optimizer may not be able to find the desired shape, even with the guide. In theory, this should result in a TIME_OUT forcing failure reason, but it doesn't always. You should verify that the plan is ever successfully forced before looking further for reasons it failed.

    • 2
  2. SEarle1986
    2022-09-23T07:25:47+08:002022-09-23T07:25:47+08:00

    The problem turned out not to be anything to do with constraints but is something to do with the query itself.

    A cut down, anonymized version of the query is below:

    SELECT  1
            -- some text so I can pick it out of query_store_sql_text more easily
            FROM    Object1 WITH (NOLOCK)
            INNER JOIN Object2 Object2 WITH (NOLOCK) ON ? = Object2.Column1
                AND ? = Object2.Column2
                AND Object1.Column3 = Object2.Column4
            INNER JOIN Object3 Object3 WITH (NOLOCK) ON Object1.Column5 = Object3.Column5
                AND Object1.Column6 >= Object3.Column7
                AND Object3.Column8 IS NULL
            INNER JOIN Object4 Object5 WITH (NOLOCK) ON ? = Object5.Column9
            LEFT JOIN Object4 WITH (NOLOCK) ON Object4.Column9 = ?
            LEFT JOIN Object6 ON Object6.Column10 = CAST(Object5.Column4 + ? AS VARCHAR(255))
                AND Object6.Column11 = Object1.Column12
                AND Object6.Column13 = Object3.Column13
                AND Object6.Column5 = Object3.Column5
                AND Object6.Column14 = ?
    WHERE   (Object4.Column4 = ? OR Object4.Column4 IS NULL)
    

    the plan is here

    I

    • Run the query
    • get the query_id and plan_id from the query store dmvs
    • force the query to the plan
    • run the query again
    • the plan shows as NO_PLAN in sys.query_store_plan.last_force_failure_reason_desc

    Consegui rastrear isso até a cláusula WHERE (a cláusula where é muito maior na consulta real, mas comentar bits um por levar a esse predicado ser o problema)

    Ainda não consigo explicar por que, mas agora tenho um exemplo reproduzível em meu ambiente. Só preciso ver se consigo replicar isso no AdventureWorks.

    Estou marcando a resposta de Paul Whites como a resposta aceita, pois em termos da teoria original das restrições estar com defeito, está correta

    • 0

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