提高 CASE 选择性能

ris*_*ism 7 performance sql-server sql-server-2008-r2 case query-performance

我有以下查询,在少于 100K 行的数据集上运行最多需要 2 秒。

我的 SQL 非常生疏,但这看起来像是做的工作比它应该做的多。任何人都可以提供一些关于在哪里寻找加快速度的指示吗?

SELECT
    a.AddressID,
    IsPrincipal = CASE
    WHEN EXISTS(SELECT TOP 1 1 FROM dbo.Setting s WHERE s.SettingValue = a.AddressID AND s.SettingDefinitionID = 3 AND s.ProfileID = 1)
                THEN 1
                ELSE 0
            END,
    IsPickUp = CASE
                WHEN EXISTS(SELECT TOP 1 1 FROM dbo.AddressRole ar WHERE ar.AddressID = a.AddressID AND ar.[AddressRoleTypeID] = 2)
                THEN 1
                ELSE 0
            END,
    IsSender = CASE
                WHEN EXISTS(SELECT TOP 1 1 FROM dbo.AddressRole ar WHERE ar.AddressID = a.AddressID AND ar.[AddressRoleTypeID] = 3)
                THEN 1
                ELSE 0
            END,
            IsDelivery = CASE
                WHEN EXISTS(SELECT TOP 1 1 FROM dbo.AddressRole ar WHERE ar.AddressID = a.AddressID AND ar.[AddressRoleTypeID] = 4)
                THEN 1
                ELSE 0
            END,
    IsReceiver = CASE
                WHEN EXISTS(SELECT TOP 1 1 FROM dbo.AddressRole ar WHERE ar.AddressID = a.AddressID AND ar.[AddressRoleTypeID] = 5)
                THEN 1
                ELSE 0
            END
        FROM dbo.[Address] AS a
        WHERE a.MFTID = '12345'
Run Code Online (Sandbox Code Playgroud)

men*_*osi 7

您可以像这样连接AddressRoleSetting表,而不是对每一行进行这样的查找:

SELECT
    a.AddressID,
    IsPrincipal = Max(iif(s.SettingValue Is Not Null, 1, 0)),
    IsPickUp = Max(iif(ar.AddressRoleTypeID = 2, 1, 0)),
    IsSender = Max(iif(ar.AddressRoleTypeID = 3, 1, 0)),
    IsDelivery = Max(iif(ar.AddressRoleTypeID = 4, 1, 0)),
    IsReceiver = Max(iif(ar.AddressRoleTypeID = 5, 1, 0))
  FROM dbo.[Address] AS a
  Left Join dbo.Setting As s
    On a.AddressID = s.SettingValue
    And s.SettingDefinitionID = 3
    And s.ProfileID = 1
  Left Join dbo.AddressRole As ar
    On a.AddressID = ar.AddressID
  WHERE a.MFTID = '12345'
  Group By a.AddressID;
Run Code Online (Sandbox Code Playgroud)

这应该会减少执行的连接次数,并且不会更改结果集的基数。

我添加了MAX以便我可以做一个GROUP BY,因为我完全期望AddressRole表格中的每一行可能有不止一行Address。通过这种方式,我们将基数保持为与Address表相同,但我们可以查看表中的任何行是否AddressRole包含AddressRoleTypeID我们正在寻找的值。

MAXGROUP BY不需要的,如果你的原始查询无子查询TOP返回一行。