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 命令中使用 CASE
、WHEN
、THEN
(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 块语句总是进行扫描,并降低性能。
我有这张表:
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 命令中使用 CASE
、WHEN
、THEN
(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 块语句总是进行扫描,并降低性能。