我的任务是改善完全非规范化的表的性能。
它有30列,但是为了简单起见,我的示例有4列。
CREATE TABLE (
Id UNIQUEIDENTIFIER NOT NULL,
Location1 NVARCHAR(MAX) NULL,
Location2 NVARCHAR(MAX) NULL,
Location3 NVARCHAR(MAX) NULL,
...
PersonId UNIQUEIDENTIFIER NULL
)
这包含位置的层次结构,并且在层次结构的末尾是分配给该位置的人员。
示例数据为:
- 建筑物A,NULL,NULL,NULL,NULL
- A楼底层NULL,NULL,NULL
- 第1楼底层A楼,NULL,NULL
- 第1部分第1室第一层A楼,空
- 'Craig'1号厅1楼A楼
- “约翰”第1部分1楼A楼
- 第2楼底层A楼,NULL,NULL
- 第1部分第2楼第一层A楼,空
- “彼得”一室2楼A楼
因此,在这种情况下,我们有2个房间及其等级。第1部分的1号房间有2个人,第2部分的1号房间只有一个人。
令人印象深刻的桌子设计,我知道。
我要求我们放弃NVARCHAR(MAX)
。这已更改为VARCHAR(80)
。现在,这使我可以使用索引。我的问题是关于要使用的索引类型。
要找到所选行的父级,我需要这样做:
SELECT *
FROM MyTable
WHERE ISNULL(Location1,'') = ISNULL(MyLocation1,'') AND
ISNULL(Location2,'') = ISNULL(MyLocation2,'') AND
ISNULL(Location3,'') = ISNULL(MyLocation3,'')
绝大多数查询都遵循这种模式。在“位置X”列中。
我不确定是否应该为每列创建一个索引。...,还是应该创建一个覆盖所有列的索引...,或者应为每列一个索引,包括其余列。
所以
OR
OR
我不确定要获得最佳效果的方向。
答案 0 :(得分:0)
您应该在(location1, location2, location3)
上创建索引-覆盖索引。
但是,您对NULL
值有疑问。这些将阻碍索引的使用。为防止这种情况,请将默认值从NULL
更改为''
:
CREATE TABLE t (
Id UNIQUEIDENTIFIER NOT NULL,
Location1 NVARCHAR(80) NOT NULL DEFAULT '',
Location2 NVARCHAR(80) NOT NULL DEFAULT '',
Location3 NVARCHAR(80) NOT NULL DEFAULT '',
. . .
)
答案 1 :(得分:0)
在所有相关列(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
,您似乎可以确定可以安全地使用''
值代替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,'') + '|'
OR
SELECT *
FROM MyTable
WHERE
LocationAll LIKE
ISNULL(MyLocation1,'') + '|'
ISNULL(MyLocation2,'') + '|'
ISNULL(MyLocation3,'') + '|' + '%'