Pergunta

Alguém tem uma consulta que pesquisa no cache do plano de SQL2005/2008, identificando consultas ou procedimentos armazenados que possuem varreduras de tabela/índice em seus planos de execução?

Foi útil?

Solução

Pinal Dave realmente fez um post sobre isso e com um pouco de alteração em seu artigo original (quase nenhuma alteração necessária!) Você pode obter a resposta certa. Se ele tem uma conta, credite -o :)

http://blog.sqlauthority.com/2009/03/17/sql-sherver-practical-sql-sherver-xml-part-one-query-plan-cache-e-cost-of-operations-in-the- cache/

Sua consulta é:

WITH XMLNAMESPACES(DEFAULT N'http://schemas.microsoft.com/sqlserver/2004/07/showplan'),
CachedPlans
(
ParentOperationID,
OperationID,
PhysicalOperator,
LogicalOperator,
EstimatedCost,
EstimatedIO,
EstimatedCPU,
EstimatedRows,
PlanHandle,
QueryText,
QueryPlan,
CacheObjectType,
ObjectType)
AS
(
SELECT
RelOp.op.value(N'../../@NodeId', N'int') AS ParentOperationID,
RelOp.op.value(N'@NodeId', N'int') AS OperationID,
RelOp.op.value(N'@PhysicalOp', N'varchar(50)') AS PhysicalOperator,
RelOp.op.value(N'@LogicalOp', N'varchar(50)') AS LogicalOperator,
RelOp.op.value(N'@EstimatedTotalSubtreeCost ', N'float') AS EstimatedCost,
RelOp.op.value(N'@EstimateIO', N'float') AS EstimatedIO,
RelOp.op.value(N'@EstimateCPU', N'float') AS EstimatedCPU,
RelOp.op.value(N'@EstimateRows', N'float') AS EstimatedRows,
cp.plan_handle AS PlanHandle,
st.TEXT AS QueryText,
qp.query_plan AS QueryPlan,
cp.cacheobjtype AS CacheObjectType,
cp.objtype AS ObjectType
FROM sys.dm_exec_cached_plans cp
CROSS APPLY sys.dm_exec_sql_text(cp.plan_handle) st
CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle) qp
CROSS APPLY qp.query_plan.nodes(N'//RelOp') RelOp (op)
)
SELECT
PlanHandle,
ParentOperationID,
OperationID,
PhysicalOperator,
LogicalOperator,
QueryText,
CacheObjectType,
ObjectType,
EstimatedCost,
EstimatedIO,
EstimatedCPU,
EstimatedRows
FROM CachedPlans
WHERE CacheObjectType = N'Compiled Plan'

E o que você deseja no final é especificamente os tipos de varredura (agrupados, tabela e índice)

and
(PhysicalOperator = 'Clustered Index Scan' or PhysicalOperator = 'Table Scan' 
or PhysicalOperator = 'Index Scan')

A consulta básica para obter o cache do plano não é difícil, e você pode fazer manualmente o XQuery, mas, para ser justo, o Pinal fez uma ótima versão para que não a reinvente.

Outras dicas

Demorou um pouco para convencê -lo a me dar a resposta, mas é uma pequena alteração no final. Se você deseja o nome do objeto que está causando a varredura, ele será feito, mas há problemas.

Há uma coisa que está limitando a eficácia disso. O escopo do object_name / sys.objects é para o seu banco de dados, então você está extraindo todos os planos do cache para qualquer banco de dados, mas só pode nomear aqueles que estão dentro do banco de dados que você está usando atualmente.

Os IDs de objeto não são guarentes para serem únicos entre os bancos de dados, por isso há uma chance de o ID ter correspondido ao seu banco de dados atual, assim como em outro e você receberá um nome incorreto devolvido por ele, por isso não é perfeito por qualquer meio.

Da mesma forma, se você vir alguma coisa com um ID de objeto> 0, mas nenhum nome dado significa que o plano era de um objeto não uma consulta do ADHOC, mas as informações sobre esse nome estão em uma exibição do sistema em um banco de dados diferente dentro do servidor.

Em um servidor dentro de um único banco de dados, pelo menos seria correto, mas pegue o nome que fornece como uma indicação, não o evangelho.

WITH XMLNAMESPACES
(DEFAULT N'http://schemas.microsoft.com/sqlserver/2004/07/showplan'),
CachedPlans
(
ParentOperationID,
OperationID,
PhysicalOperator,
LogicalOperator,
EstimatedCost,
EstimatedIO,
EstimatedCPU,
EstimatedRows,
PlanHandle,
QueryText,
QueryPlan,
CacheObjectType,
ObjectType,
ObjectID)
AS
(
    SELECT
    RelOp.op.value(N'../../@NodeId', N'int') AS ParentOperationID,
    RelOp.op.value(N'@NodeId', N'int') AS OperationID,
    RelOp.op.value(N'@PhysicalOp', N'varchar(50)') AS PhysicalOperator,
    RelOp.op.value(N'@LogicalOp', N'varchar(50)') AS LogicalOperator,
    RelOp.op.value(N'@EstimatedTotalSubtreeCost ', N'float') AS EstimatedCost,
    RelOp.op.value(N'@EstimateIO', N'float') AS EstimatedIO,
    RelOp.op.value(N'@EstimateCPU', N'float') AS EstimatedCPU,
    RelOp.op.value(N'@EstimateRows', N'float') AS EstimatedRows,
    cp.plan_handle AS PlanHandle,
    st.TEXT AS QueryText,
    qp.query_plan AS QueryPlan,
    cp.cacheobjtype AS CacheObjectType,
    cp.objtype AS ObjectType,
    qp.objectid
    FROM sys.dm_exec_cached_plans cp
    CROSS APPLY sys.dm_exec_sql_text(cp.plan_handle) st
    CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle) qp
    CROSS APPLY qp.query_plan.nodes(N'//RelOp') RelOp (op)
)

SELECT 
PlanHandle,
ParentOperationID,
OperationID,
PhysicalOperator,
LogicalOperator,
QueryText,
CacheObjectType,
ObjectType,
EstimatedCost,
EstimatedIO,
EstimatedCPU,
EstimatedRows,
QueryPlan,
C.ObjectID,
Object_Name(C.ObjectID)
FROM CachedPlans C
Where 
(PhysicalOperator = 'Clustered Index Scan' 
  or 
PhysicalOperator = 'Table Scan' 
 or 
PhysicalOperator = 'Index Scan'
)
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top