【问题标题】:Design change not to use Dynamic SQL?设计更改不使用动态 SQL?
【发布时间】:2016-01-28 20:22:25
【问题描述】:

SQL Server 2012 中的批处理(嵌套存储过程)存在零星的性能问题。有时,它需要的时间比平时长得多。

该过程根据输入参数重建某些表。 RULE 表有一个语句列,该列有 70 多个不同的语句(涉及 20 多个不同的列),用于动态 sql 中的 WHERE 子句。

所以,DELETE,在每个进程运行时,不仅参数不同,WHERE子句中的列类型和列数也不同。

除了管理统计信息和索引调整之外,您还有什么建议?开发团队对代码和架构更改持开放态度。

SELECT rul.SQL_STATEMENT
FROM APP_RULE rul
LEFT JOIN APP_RULE_EXCEPTION exc
    ON rul.RULE_ID = exc.RULE_ID
WHERE rul.APP_ID = @AppId 
    AND (exc.RULE_ID IS NULL OR exc.RULE_ID NOT IN (
    SELECT RULE_ID FROM APP_RULE_EXCEPTION ))

SET @SQLStatement = 
    'DELETE FROM EMPLOYEE ' +
    'WHERE APP_ID = ' + CAST(@AppId AS VARCHAR(10)) + 
     ' AND EMPLOYEE_ID NOT IN (' +
           'SELECT EMPLOYEE_ID FROM EMPLOYEE_NEW '  +
           'WHERE '+ @SQLStatement + ')'
EXEC (@SQLStatement)

SET @SQLStatement = 
    'DELETE FROM ' + @TableName + ' ' +
    'WHERE EMPLOYEE_ID NOT IN (' +
           'SELECT EMPLOYEE_ID FROM EMPLOYEE_STG '  +
           'WHERE APP_ID = ' + CAST(@AppId AS VARCHAR(10)) +''')'
EXEC (@SQLStatement)

SET @SQLStatement = 
    'INSERT INTO ' + @DestinationTable + ' '+'( [APP_ID], ' + @AttributeList + ')'+
    'SELECT ' + CAST(@AppId AS VARCHAR(10)) + ',''' +  @ExposedAttributeList + 
    'FROM ' + @SourceTable + ' ' +
    'WHERE [DATE] = ''' + @TDate + ''''  
EXEC (@SQLStatement)              

以下是动态 sql 生成的两个 DELETE 示例。

DELETE FROM EMPLOYEE WHERE APP_ID = 103 AND APP_TYPE = 'IE' AND EMPLOYEE_ID NOT IN (
    SELECT EMPLOYEE_ID FROM EMPLOYEE_NEW WHERE APP_TYPE = 'IE' )

DELETE FROM EMPLOYEE WHERE APP_ID = 103 AND APP_TYPE = 'IE' AND COUNTRY='USA' AND EMPLOYEE_ID NOT IN (
    SELECT EMPLOYEE_ID FROM EMPLOYEE_NEW WHERE APP_TYPE = 'IE' AND EMPLOYEE_ID IN (
        SELECT EMPLOYEE_ID FROM EMPLOYEE_EMAIL WHERE ISNULL(EMAIL_ADDRESS,'')<>'' and EType='OFFICE' ))

谢谢, 库泽

【问题讨论】:

  • 使用 WITH RECOMPILE 可能会有所帮助。另外,请参见此处:sommarskog.se/query-plan-mysteries.html
  • 根据这个问题中显示的内容无法知道问题出在哪里。这个问题本身表明对如何优化基于 SQL 的流程知之甚少。我建议您做以下两件事之一:A) 聘请一位知道自己在做什么的 DBA,或 B) 购买性能监控工具来确定您遇到性能问题的位置和原因。任何人都无法查看您向我们展示的内容,也无法判断他们当前的系统设计和架构是好还是坏。它可能从根本上是好的,一个小的改变将解决这个问题。

标签: sql-server performance tsql dynamic


【解决方案1】:

您应该做的第一件事是了解问题所在。当某件事随机运行很长时间时,通常会得到非最佳查询计划,假设您已经检查过没有同时发生阻塞。

您应该查看计划缓存,看看计划与不同情况下的 CPU 和 IO 测量值有什么区别。

以下是可用于查看计划缓存的简短 SQL:

select top 100
SUBSTRING(t.text, (s.statement_start_offset/2)+1,
((CASE s.statement_end_offset WHEN -1 THEN DATALENGTH(t.text) ELSE s.statement_end_offset END 
- s.statement_start_offset)/2) + 1) as statement_text,
t.text,
s.total_logical_reads, s.total_logical_reads / s.execution_count as avg_logical_reads,
s.total_worker_time, s.total_worker_time / s.execution_count as avg_worker_time,
s.execution_count,
max_logical_reads,
creation_time,
last_execution_time
--,cast(p.query_plan as xml) as query_plan
from sys.dm_exec_query_stats s
cross apply sys.dm_exec_sql_text (sql_handle) t
--cross apply sys.dm_exec_text_query_plan (plan_handle, statement_start_offset, statement_end_offset) p
order by s.total_logical_reads desc

这将显示从仍在缓存中的计划中收集的所有测量值。当计划被放弃时,测量也将被删除。测量是针对该计划自创建以来的所有执行情况。

注释掉的部分是语句的计划,从那里您可以看到运算符和估计的行数。不要看计划中的百分比,这些是基于估计的,可能完全错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-28
    • 2014-02-20
    相关资源
    最近更新 更多