SELECT 通过具有索引的多列之一

SELECT by one of multiple columns with index

我有这张表:

    CREATE TABLE [Person].[Address](
       [AddressID] [int] NOT NULL,
       [AddressLine1] [nvarchar](60) NOT NULL,
       [StateProvinceID] [int] NOT NULL,

    CONSTRAINT [PK_Address_AddressID] PRIMARY KEY CLUSTERED 
    (
       [AddressID] ASC
    )
    ) 
    GO

有了这个额外的非聚集索引。

    CREATE UNIQUE NONCLUSTERED INDEX [IX_Address_AddressLine1_StateProvinceID 
    ON   [Person].[Address]
    (
       [AddressLine1] ASC,
       [StateProvinceID] ASC,
    )
    GO

我正在使用现有的应用程序代码。该应用程序将向我的查询传递两个参数,但其中一个可能等于“-1”。当它这样做时,目的是匹配该参数的所有行。

当前查询如下所示:

    Select AddressID, AddressLine1, StateProvinceID
    From Person.Address
    Where ((AddressID = @AddressID) or (@AddressID=-1))
    and ((StateProvinceID = @StateProvinceID) or (@AddressID=-1))

这个returns当@AddressID或@StateProvinceID等于'-1'时需要的数据,它本质上是忽略(-1=-1 returns TRUE)

问题出在索引上。当我这样做时,它会进行扫描,而不是搜索。

本returns一求:

    Select AddressID, AddressLine1, StateProvinceID
    From Person.Address
    Where AddressID = @AddressID 
    and StateProvinceID = @StateProvinceID

...虽然当前查询扫描速度慢得多。

第二个查询很快,但没有按我需要的方式工作。

有没有办法允许绕过一个或另一个参数,同时仍然使用索引查找?

在 sql 命令中使用 CASEWHENTHEN (link)。希望对你有帮助。

Select AddressID, AddressLine1, StateProvinceID
From Person.Address
Where AddressID = CASE WHEN @AddressID = -1 THEN AddressID ELSE @AddressID END AND
      StateProvinceID = CASE WHEN @StateProvinceID = -1 THEN StateProvinceID ELSE @StateProvinceID END

我认为,如果您将包含以下列的索引更新为:[AddressLine1] 和 [StateProvinceID] 到 [StateProvinceID] 和 [AddressLine1](将 StateProvinceID 放在索引的第一位),查询应该使用此索引而不是完整的 table扫描.

单个 SQL 语句中的分支逻辑似乎总是 return SCAN 而不是 SEEK。

我最终解决这个问题的方法是编写明确的(丑陋的)分支逻辑来为我想要的条件选择一个简单的查询。

在我的例子中,有两个参数。目标是当给定参数 = -1 时匹配所有记录,基本上忽略 where 子句中的那个参数。

使用两个参数,有 4 种可能的情况。

  • parm1 设置,parm2 -1(忽略)
  • parm1 -1(忽略),parm2 设置
  • parm1 已设置,parm2 已设置
  • parm1 -1(忽略),parm2 -1(忽略)<-returns 所有行

所以我用 4 个 If 语句编写了分支逻辑。

如果参数 1 <> -1 且参数 2 = -1

 - then do a simple query that only uses parm1

如果参数 1 = -1 且参数 2 <> -1

 - then do a simple query that only uses parm2

等...

虽然非常难看,但 return 每次都是 SEEK。丑陋但非常快的代码。更漂亮的 "When, Then, Else" SINGULAR 块语句总是进行扫描,并降低性能。