1

我在 ASP.NET 应用程序中有一段代码,它从参数列表构建 SQL 查询。参数的数量可能会有所不同,因此可以将各种条件添加到此查询中。数据库是 Microsoft SQL Server 2008。

所有 AND 和 OR 都是以编程方式生成的。

该查询的执行时间超过 3 秒,但经过一些分析和索引后,它的运行时间不到一秒。我仍然认为查询本身可以优化。我看过执行计划,但这对我来说意义不大——不是 SQL 专家。

我想知道查询是否可以以更智能的方式完成 - 我无法弄清楚。下面是一个查询示例:

 SELECT [id], [WorkTitle], [CreateDate], [UpdateDate], [Writer], [ValidFrom], 

[ValidTo], [Text] 
 FROM dbo.Texts T  
 WHERE Category_id = 3 AND '2012-11-06' BETWEEN ValidFrom AND ValidTo  
 AND (EXISTS (SELECT 'X' FROM dbo.Criteria_List CL WHERE T.id = CL.Text_id   AND CL.Criteria_id = 1 AND CL.Value = '95068')       
    OR NOT EXISTS (SELECT 'X' FROM dbo.Criteria_List CL WHERE T.id = CL.Text_id AND CL.Criteria_id = 1))  

 AND (EXISTS (SELECT 'X' FROM dbo.Criteria_List CL WHERE T.id = CL.Text_id   AND CL.Criteria_id = 2 AND CL.Value = 'C')       
    OR NOT EXISTS (SELECT 'X' FROM dbo.Criteria_List CL WHERE T.id = CL.Text_id AND CL.Criteria_id = 2))  

 AND (EXISTS (SELECT 'X' FROM dbo.Criteria_List CL WHERE T.id = CL.Text_id   AND CL.Criteria_id = 3 AND CL.Value = 'HEL')       
    OR NOT EXISTS (SELECT 'X' FROM dbo.Criteria_List CL WHERE T.id = CL.Text_id AND CL.Criteria_id = 3))  

 AND (EXISTS (SELECT 'X' FROM dbo.Criteria_List CL WHERE T.id = CL.Text_id   AND CL.Criteria_id = 4 AND CL.Value = 'CC')      
    OR NOT EXISTS (SELECT 'X' FROM dbo.Criteria_List CL WHERE T.id = CL.Text_id AND CL.Criteria_id = 4))  

 AND (EXISTS (SELECT 'X' FROM dbo.Criteria_List CL WHERE T.id = CL.Text_id   AND CL.Criteria_id = 5 AND CL.Value = NULL)     
    OR NOT EXISTS (SELECT 'X' FROM dbo.Criteria_List CL WHERE T.id = CL.Text_id AND CL.Criteria_id = 5))  

 AND (EXISTS (SELECT 'X' FROM dbo.Criteria_List CL WHERE T.id = CL.Text_id   AND CL.Criteria_id = 7 AND CL.Value = '321')      
    OR NOT EXISTS (SELECT 'X' FROM dbo.Criteria_List CL WHERE T.id = CL.Text_id AND CL.Criteria_id = 7))  

 AND (EXISTS (SELECT 'X' FROM dbo.Criteria_List CL WHERE T.id = CL.Text_id   AND CL.Criteria_id = 9 AND CL.Value = 'DK7778')    
    OR NOT EXISTS (SELECT 'X' FROM dbo.Criteria_List CL WHERE T.id = CL.Text_id AND CL.Criteria_id = 9))  

 AND (EXISTS (SELECT 'X' FROM dbo.Criteria_List CL WHERE T.id = CL.Text_id   AND CL.Criteria_id = 10 AND CL.Value = 'TFS')   
    OR NOT EXISTS (SELECT 'X' FROM dbo.Criteria_List CL WHERE T.id = CL.Text_id AND CL.Criteria_id = 10)) 

 AND (EXISTS (SELECT 'X' FROM dbo.Criteria_List CL WHERE T.id = CL.Text_id   AND CL.Criteria_id = 11 AND CL.Value = 'TMP')   
    OR NOT EXISTS (SELECT 'X' FROM dbo.Criteria_List CL WHERE T.id = CL.Text_id AND CL.Criteria_id = 11)) 

 AND (EXISTS (SELECT 'X' FROM dbo.Criteria_List CL WHERE T.id = CL.Text_id   AND CL.Criteria_id = 13 AND CL.Value = 'OY-VKB')   
    OR NOT EXISTS (SELECT 'X' FROM dbo.Criteria_List CL WHERE T.id = CL.Text_id AND CL.Criteria_id = 13)) 

任何提示和技巧表示赞赏。

干杯詹斯

4

2 回答 2

2
  • 对于表Texts,我会在 上添加一个索引(Category_id, ValidFrom) INCLUDE (ValidTo),如果没有的话。(如果您已经在 any(Category_id, ValidFrom, ValidTo)或 on 上有索引(Category_id, ValidFrom),它们也可能非常好。

  • 对于Criteria_List表来说,一个索引(Text_id, Criteria_id, Value)可能足以让优化器产生一个好的执行计划。

    第二个选项(或者甚至更好,您必须使用表大小和分布来测试执行计划和运行时间)将是两个索引,一个 on(Criteria_id, Text_id)和一个 on (Criteria_id, Value, Text_id)


您可以像这样重写 10 个条件 - 但无论如何都应该注意索引:

 WHERE Category_id = 3 AND '2012-11-06' BETWEEN ValidFrom AND ValidTo  
 AND NOT EXISTS ( SELECT 'X' FROM dbo.Criteria_List CL 
                  WHERE T.id = CL.Text_id AND CL.Criteria_id = 1 
                    AND (CL.Value <> '95068' OR CL.Value IS NULL)
                ) 
 AND NOT EXISTS ( SELECT 'X' FROM dbo.Criteria_List CL 
                  WHERE T.id = CL.Text_id AND CL.Criteria_id = 2 
                    AND (CL.Value <> 'C' OR CL.Value IS NULL)
                ) 
 ...
 AND NOT EXISTS ( SELECT 'X' FROM dbo.Criteria_List CL 
                  WHERE T.id = CL.Text_id AND CL.Criteria_id = 5 
                    AND (CL.Value IS NOT NULL)
                ) 
 ...
于 2012-11-05T12:56:37.977 回答
0

我建议的一件事是更改您的数据库设计,以便您可以识别 CriteriaList.value 记录,而不是按原样列出它们。这将使您的查询更加灵活,并意味着您应该能够摆脱所有或大部分存在/不存在的问题,并可能加快您的查询速度。

于 2012-11-05T12:29:21.313 回答