sql - 单个指数 vs 覆盖指数
问题描述
我的任务是提高完全非规范化的表的性能。
它有 30 列,但为了简单起见,我的示例有 4 列。
CREATE TABLE (
Id UNIQUEIDENTIFIER NOT NULL,
Location1 NVARCHAR(MAX) NULL,
Location2 NVARCHAR(MAX) NULL,
Location3 NVARCHAR(MAX) NULL,
...
PersonId UNIQUEIDENTIFIER NULL
)
这包含位置的层次结构,并且在层次结构的末尾是分配到该位置的人员。
示例数据为:
- A楼,空,空,空,空
- A楼,底层,NULL,NULL,NULL
- A 楼,底层,第 1 部分,NULL,NULL
- A 楼底层 1 区 1 室 NULL
- A 楼,底层,第 1 部分,1 号房间,“Craig”
- A 楼底层 1 区 1 室“约翰”
- A 楼,底层,第 2 部分,NULL,NULL
- A 楼底层 2 区 1 室 NULL
- A 楼,一楼,第 2 部分,房间 1,“彼得”
所以,在这种情况下,我们有 2 个房间,它们的层次结构。Section 1 的 Room 1 有 2 人,Section 2 的 Room 1 有一个人。
令人印象深刻的桌子设计,我知道。
我所做的是要求我们放弃NVARCHAR(MAX)
. 这已更改为VARCHAR(80)
. 这现在允许我使用索引。我的问题是关于要使用的索引类型。
要查找所选行的父级,我需要执行以下操作:
SELECT *
FROM MyTable
WHERE ISNULL(Location1,'') = ISNULL(MyLocation1,'') AND
ISNULL(Location2,'') = ISNULL(MyLocation2,'') AND
ISNULL(Location3,'') = ISNULL(MyLocation3,'')
绝大多数查询都遵循这种模式。'WHERE'ing LocationX 列。
我不确定是否应该为每列创建一个索引……或者,我是否应该创建一个涵盖所有列的索引……或者,每列一个索引,包括剩余的列。
所以,
- Location1 上的索引,Location2 上的索引 .. 等
或者
- 位置 1、位置 2 上的索引 ....
或者
- Location1 上的索引 INCLUDE (Location2, Location3...) Location2 上的索引 INCLUDE (Location1, Location3...)
我不确定该往哪个方向发展,以获得最佳性能。
解决方案
所有相关列上都应该有一个索引(location1, location2, location3)
,但是这里的NULL
值有问题。
SELECT *
FROM MyTable
WHERE
ISNULL(Location1,'') = ISNULL(MyLocation1,'') AND
ISNULL(Location2,'') = ISNULL(MyLocation2,'') AND
ISNULL(Location3,'') = ISNULL(MyLocation3,'')
当您ISNULL
对列值使用函数(或几乎任何函数)时,通常无法使用索引。您可以通过查看执行计划来确认。
如果您编写这样的查询:
SELECT *
FROM MyTable
WHERE
Location1 = ISNULL(MyLocation1,'') AND
Location2 = ISNULL(MyLocation2,'') AND
Location3 = ISNULL(MyLocation3,'')
将使用索引,但查询不会产生正确的结果。
查看您如何编写查询和使用ISNULL
,看起来您确信''
可以安全地使用 value 而不是NULL
. 理想情况下,应制作所有这些列NON-NULL
并将所有NULL
值替换为''
.
由于您不能这样做,因此处理它的一种方法是为每LocationN
列创建计算的持久列,然后在这些计算列上创建索引并在查询中使用这些计算列:
CREATE TABLE dbo.MyTable
(
ID int NOT NULL IDENTITY (1, 1),
Location1 varchar(80) NULL,
Location2 varchar(80) NULL,
Location3 varchar(80) NULL,
Location1_ AS ISNULL(Location1, '') PERSISTED,
Location2_ AS ISNULL(Location2, '') PERSISTED,
Location3_ AS ISNULL(Location3, '') PERSISTED
)
创建索引
CREATE NONCLUSTERED INDEX [IX] ON [dbo].[MyTable]
(
[Location1_] ASC,
[Location2_] ASC,
[Location3_] ASC
)
询问
SELECT *
FROM MyTable
WHERE
Location1_ = ISNULL(MyLocation1,'') AND
Location2_ = ISNULL(MyLocation2,'') AND
Location3_ = ISNULL(MyLocation3,'')
此主题的另一个变体是创建单个计算列并将所有字符串与一些分隔符合并在一起,并在该单个列上创建索引。它可能更有效。
ALTER TABLE dbo.MyTable ADD
LocationAll AS
isnull([Location1],'') + '|' +
isnull([Location2],'') + '|' +
isnull([Location3],'') + '|' PERSISTED
CREATE NONCLUSTERED INDEX [IX_all] ON [dbo].[MyTable]
(
[LocationAll] ASC
)
查询将如下所示:
SELECT *
FROM MyTable
WHERE
LocationAll =
ISNULL(MyLocation1,'') + '|'
ISNULL(MyLocation2,'') + '|'
ISNULL(MyLocation3,'') + '|'
或者
SELECT *
FROM MyTable
WHERE
LocationAll LIKE
ISNULL(MyLocation1,'') + '|'
ISNULL(MyLocation2,'') + '|'
ISNULL(MyLocation3,'') + '|' + '%'
推荐阅读
- asp.net-core - 验证 CQRS + EventSourcing 中的现有实体。微服务 ASP.NET Core 5.0
- python - 尝试通过索引获取元组中的对象时,Python 中出现“TypeError:‘元组’对象不可调用”错误
- c - 这段代码有什么问题?它正确显示输出,但以退出状态 56 结束。这是什么意思?
- python - Python PriorityQueue 仅获取元组的一部分
- java - “ORA-00933:SQL 命令未正确结束”这段代码中的异常
- amazon-web-services - AWS CLI:“无法执行脚本 pyi_rth_multiprocessing”
- python - Python Sphinx 自动汇总渲染参数,如 numpy
- meshlab - 从许多 3D 对象文件自动创建地图
- assembly - 试图将 if-else 条件转换为汇编?
- javascript - JavaScript单元测试:模拟来自同一模块的其他功能