在日期范围内搜索时的复合索引设计(窄与宽)
Composite Index Design (Narrow vs Wide) when searching on date range
我和我的同事就复合索引的设计发生了争执。如果查询中使用了两个字段,我认为更独特的字段应该在第一位。
看这个例子
CREATE TABLE [dbo].[tblPurchase](
[PurchaseId] [int] NOT NULL,
[ProductId] [int] NOT NULL,
[ItemId] [int] NOT NULL,
[PurchaseDate] [date] NOT NULL,
[CurrencyId] [int] NOT NULL,
...
...
...
CONSTRAINT [PK_tblPurchase] PRIMARY KEY CLUSTERED
(
[PurchaseId] ASC,
[ProductId] ASC,
[ItemId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
目前我们有 2 种货币,我们有大约 200 万条记录(注意:我们可能会在不久的将来添加 2 种新货币)。
我决定使用 [PurchaseDate]-[CurrencyId]
作为复合索引创建一个索引,但我的同事认为我们应该将其翻转为使用 [CurrencyId]-[PurchaseDate]
,因为 CurrencyId 不那么唯一。我们的查询是:
SELECT *
FROM [tblPurchase]
WHERE [PurchaseDate] >= '2022-01-01' AND [PurchaseDate] <= '2022-06-01' AND [CurrencyId] = 1
有什么想法吗?
的最佳索引
WHERE PurchaseDate >= '2022-01-01' AND PurchaseDate <= '2022-06-01' AND CurrencyId = 1
是[CurrencyId]-[PurchaseDate]
这与选择性无关。
它可以使用第一列在 CurrencyId
上进行相等搜索,然后在第二列上进行范围搜索,以便准确读取正确的行来解决查询。
对于反向索引顺序,它可以做的最好的事情是在日期谓词上进行范围查找,然后是剩余谓词以丢弃为其他货币读取的行。因此在这种情况下索引查找将读取更多行(假设日期范围内存在其他货币 ID 而不仅仅是 1
)。
要使用 phone 书籍类比(按姓氏、名字排序),这与直接查找所有 Smiths 的方式相同从 Alice 到 Bob 的名称(找到 Alice Smith starts/would 所在的点,然后读取所有条目,直到找到第一个在之后排序的条目“鲍勃史密斯”)
但是要用它来查找姓氏从 Clark 到 Davis[ 的所有 Alices 需要做更多的工作=34=](SQL 服务器将读取从 Clark 到 Davis 的所有条目并丢弃非 Alice 的条目)
我和我的同事就复合索引的设计发生了争执。如果查询中使用了两个字段,我认为更独特的字段应该在第一位。
看这个例子
CREATE TABLE [dbo].[tblPurchase](
[PurchaseId] [int] NOT NULL,
[ProductId] [int] NOT NULL,
[ItemId] [int] NOT NULL,
[PurchaseDate] [date] NOT NULL,
[CurrencyId] [int] NOT NULL,
...
...
...
CONSTRAINT [PK_tblPurchase] PRIMARY KEY CLUSTERED
(
[PurchaseId] ASC,
[ProductId] ASC,
[ItemId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
目前我们有 2 种货币,我们有大约 200 万条记录(注意:我们可能会在不久的将来添加 2 种新货币)。
我决定使用 [PurchaseDate]-[CurrencyId]
作为复合索引创建一个索引,但我的同事认为我们应该将其翻转为使用 [CurrencyId]-[PurchaseDate]
,因为 CurrencyId 不那么唯一。我们的查询是:
SELECT *
FROM [tblPurchase]
WHERE [PurchaseDate] >= '2022-01-01' AND [PurchaseDate] <= '2022-06-01' AND [CurrencyId] = 1
有什么想法吗?
WHERE PurchaseDate >= '2022-01-01' AND PurchaseDate <= '2022-06-01' AND CurrencyId = 1
是[CurrencyId]-[PurchaseDate]
这与选择性无关。
它可以使用第一列在 CurrencyId
上进行相等搜索,然后在第二列上进行范围搜索,以便准确读取正确的行来解决查询。
对于反向索引顺序,它可以做的最好的事情是在日期谓词上进行范围查找,然后是剩余谓词以丢弃为其他货币读取的行。因此在这种情况下索引查找将读取更多行(假设日期范围内存在其他货币 ID 而不仅仅是 1
)。
要使用 phone 书籍类比(按姓氏、名字排序),这与直接查找所有 Smiths 的方式相同从 Alice 到 Bob 的名称(找到 Alice Smith starts/would 所在的点,然后读取所有条目,直到找到第一个在之后排序的条目“鲍勃史密斯”)
但是要用它来查找姓氏从 Clark 到 Davis[ 的所有 Alices 需要做更多的工作=34=](SQL 服务器将读取从 Clark 到 Davis 的所有条目并丢弃非 Alice 的条目)