1

我有以下查询在 sql 服务器上占用了 %15 cpu 时间。

declare
  @JobQueueId int = NULL,   @JobTypeId int = NULL,   @JobTypeIdHasValue BIT = 0,   @TargetId int = NULL,   @TargetIdHasValue BIT = 0,   
  @JobMessage nvarchar(max) = NULL,   @ComputerName nvarchar(60) = NULL,   @ComputerNameHasValue BIT = 0,   @StartedOn datetime = NULL,   
  @StartedOnHasValue BIT = 0,   @CompletedOn datetime = NULL,   @CompletedOnHasValue BIT = 0,   @SkipOrderedBy datetime = NULL,   
  @SkipOrderedByHasValue BIT = 0,   @SkipOrderedOn datetime = NULL,   @SkipOrderedOnHasValue BIT = 0,   @Attempts int = NULL,   
  @AttemptsHasValue BIT = 0,   @FailResult nvarchar(max) = NULL,   @FailResultHasValue BIT = 0,   @CreatedBy uniqueidentifier = NULL,   
  @CreatedOn datetime = NULL  



  SET TRANSACTION ISOLATION LEVEL READ COMMITTED    

  SELECT   [JobQueueId],   [JobTypeId],   [TargetId],   [JobMessage],   [ComputerName],   [StartedOn],   [CompletedOn],   [SkipOrderedBy],     [SkipOrderedOn],   [Attempts],   FailResult],   [CreatedBy],   [CreatedOn]  
  FROM      [dbo].[JobQueue]  

  WHERE   
  ([JobQueueId] = @JobQueueId OR @JobQueueId IS NULL)    
  AND ([JobTypeId] = @JobTypeId OR (@JobTypeId IS NULL AND @JobTypeIdHasValue = 0))   
  AND ([TargetId] = @TargetId OR (@TargetId IS NULL AND @TargetIdHasValue = 0))   
  AND ([JobMessage] = @JobMessage OR @JobMessage IS NULL)   
  AND ([ComputerName] = @ComputerName OR (@ComputerName IS NULL AND @ComputerNameHasValue = 0))   
  AND ([StartedOn] = @StartedOn OR (@StartedOn IS NULL AND @StartedOnHasValue = 0))   
  AND ([CompletedOn] = @CompletedOn OR (@CompletedOn IS NULL AND @CompletedOnHasValue = 0))   
  AND ([SkipOrderedBy] = @SkipOrderedBy OR (@SkipOrderedBy IS NULL AND @SkipOrderedByHasValue = 0))   
  AND ([SkipOrderedOn] = @SkipOrderedOn OR (@SkipOrderedOn IS NULL AND @SkipOrderedOnHasValue = 0))   
  AND ([Attempts] = @Attempts OR (@Attempts IS NULL AND @AttemptsHasValue = 0))   
  AND ([FailResult] = @FailResult OR (@FailResult IS NULL AND @FailResultHasValue = 0))   
  AND ([CreatedBy] = @CreatedBy OR @CreatedBy IS NULL)   
  AND ([CreatedOn] = @CreatedOn OR @CreatedOn IS NULL)    

有人可以提供任何指示来帮助我优化此查询吗?

4

2 回答 2

1

由于查询可能会缓存有利于特定参数的计划,因此不同的参数可能不会从该计划中受益太多(搜索“参数嗅探”,您会发现这是一个非常常见的问题) . 几个选项:

  1. 添加OPTION (RECOMPILE)到声明中。由于每次编译,这将花费更多,但它至少是可预测的,并且您不应该有这些巨大的波动,其中某些参数运行半秒,而另一些参数运行很长时间。
  2. 用于OPTIMIZE FOR UNKNOWN避免使用先前缓存的参数进行优化。
  3. 打开服务器级选项(通过sp_configureOptimize for ad hoc workloads(参见此处此处),并更改您的查询以使用动态 SQL。换句话说,像这样构建查询:

    DECLARE @sql NVARCHAR(MAX);
    
    SET @sql = N'SELECT ... FROM [dbo].[JobQueue] WHERE 1=1';
    
    IF @JobQueueId IS NOT NULL
      SET @sql = @sql + N' AND JobQueueId = @JobQueueId';
    
    -- ... repeat for other params
    
    EXEC sp_executesql 
      @sql,
      N'@JobQueueId INT, ..., @CreatedOn DATETIME',
      @JobQueueId, ..., @CreatedOn;
    

另见: http: //www.sommarskog.se/dynamic_sql.html#Dyn_search

于 2013-02-12T19:51:05.397 回答
1

这是一个可怕的,可怕的查询。AND 和 OR(及其模式)的绝对数量使得任何关于索引的静态推理都是徒劳的。它如此糟糕的主要原因是因为它是“通用的”:很多应该是静态的工作(比如检查@JobQueueId 是否为空)都留给了SQL Server。

由于您不会从任何类型的查询准备中获利,因此您应该以动态方式构建查询,并让 db 服务器针对每个特定情况优化您的选择。

于 2013-02-12T21:38:49.817 回答