我想优化此查询

时间:2019-01-19 08:49:27

标签: sql sql-server tsql

我有下表:

dbo.Details
Name     Type  SubType  SerialNumber  
D_01     TxA    STxA1     4            
D_02     TxB    STxB2     3            
D_03     TxC    STxC1     2            
D_04     TxD    STxD1     7           
D_05     TxD    STxD1     1            
D_06     TxD    STxD1     9            

dbo.DetailsType
Code Name
TxA   A
TxB   B
TxC   C
...

dbo.DetailsSubType
Code    Type    Name  CustomOR
STxA1   TxA     A1      1
STxA2   TxA     A2      0
STxB1   TxB     B1      1
STxB2   TxB     B2      0
STxC1   TxC     C1      1
STxC2   TxC     C2      0
STxD    TxD     D1      1

我想知道哪种查询(A或B)最适合您,请解释一下:

查询A

CREATE PROCEDURE XXX
(
    @type nvarchar(10),
    @subType nvarchar(10) = null
)
AS
BEGIN 
declare @custom bit  = 0;
if (@subType is not null)
begin
    select @custom = CustomOR from dbo.DetailsSubType where SubType = @subType
end


select 
    DTST.SubType,
    DT.SerialNumber
from dbo.Details as  DT
left join DetailsSubType as DTST
    on DT.SubType = DTST.Code
where 
    DT.Type = @type
    and
    (
      @subType is null or
      (@custom = 0 and DTST.CustomOR= 0) or 
      (@custom = 1 and DT.SubType = @subType)
    )
END 

查询B

   declare @custom bit  = 0;
if (@subType is not null)
begin
    select @custom = CustomOR from dbo.DetailsSubType where SubType = @subType
end
if (@custom = 0)
begin
        select 
            DTST.SubType,
            DT.SerialNumber
        from dbo.Details as  DT
        left join DetailsSubType as DTST
            on DT.SubType = DTST.Code
        where 
            DT.Type = @type
            and
            DTST.CustomOR = 0
end
else
begin
        select 
            DTST.SubType,
            DT.SerialNumber
        from dbo.Details as  DT
        left join DetailsSubType as DTST
            on DT.SubType = DTST.Code
        where 
            DT.Type = @type
            and
            (DTST.CustomOR = 1 and DT.SubType = @subType)
end

2 个答案:

答案 0 :(得分:0)

不幸的是,两者都不是最佳选择。我猜您担心的问题与查询的性能和执行计划有关。第二种方法肯定为SQL Server提供了优化计划的更好机会-仅仅是因为OR确实很难优化。

但是,这没有考虑“参数嗅探”。关于该主题的文章很多(here是合理的文章。)

参数嗅探意味着SQL Server在第一次调用存储过程时会编译查询。这样可以节省重新编译查询的开销-如果您有很多“小型”查询,这一点很重要。但是,对于较大的查询,傻瓜会讨价还价-因为它没有考虑表的统计信息。

我建议您调查有关此的文章。您可能会发现第二种解决方案已足够。您可能会发现仅添加option recompile就足够了。您可能会发现您希望将查询构造为动态SQL –嘿,您知道无论如何它将被重新编译。但是您将能够做出更明智的决定。

答案 1 :(得分:0)

您可以考虑编写三个对结果进行分区的查询,其中每个查询恰好处理您的一个OR谓词,然后对所有结果进行UNION。

使用伪代码:

SELECT ... FROM ... WHERE @subType is null
UNION ALL
SELECT ... FROM ... WHERE @subType is NOT null AND DTST.CustomOR = 0 AND @custom = 0
UNION ALL
SELECT ... FROM ... WHERE @subType is NOT null AND DT.SubType = @subType AND @custom = 1

话虽如此,我实际上认为您应该更改数据模型。进行此设置非常(非常慢)。您可能没有正确规范化数据库。