我有一张桌子,不幸的是,桌子是用有趣的方式设计的。它有30列,均为NVARCHAR(MAX)
。它被设计为快速的“数据仓库样式”表,但是具有事务性。
一列是bit
,称为IsPhysical
。该表具有一个PK,仅涉及索引。所有这些NVARCHAR
列都在WHERE
子句中使用。桌子不大。在10万行到50万之间。
但是由于我们执行的查询类型很常见,
WHERE
ISNULL(a.ColumnA, '') = ISNULL(b.ColumnA, '')
AND ISNULL(a.ColumnB, '') = ISNULL(b.ColumnB, '')`
其中ColumnA
,ColumnB
等的类型为NVARCHAR(MAX)
。
我们遇到了一些性能问题。
我们在WHERE
子句中经常有两列是IsActive
和IsPhysical
。因此,我将对这些应用索引,以查看是否可以获得任何好处。
所以在此之前,我做了一个查询:
SELECT *
FROM MyTable
WHERE IsActive = 1
我发现奇怪的是:为什么执行计划针对该查询报告“聚集索引扫描”?该表在Id列上有一个聚集索引-UNIQUEIDENTIFIER
。我不确定UNIQUEIDENTIFIER
上的聚集索引的好处是什么,但这还需要研究。
99%的活动。因此,我希望将索引应用于其中的某些列,但由于它们是NVARCHAR(MAX)
-该选项不可用。并且将它们更改为VARCHAR(800)
将打破8000字节的行限制。
因此,尝试TRY帮助的唯一方法是为这些IsPhysical
和IsActive
列建立索引,并可能更改PK上的索引类型?但不确定为什么,在将索引添加到这些列之前,我得到了“聚集索引扫描”。
答案 0 :(得分:0)
首先,您应该决定要对NULL
值执行什么操作,否则索引将不会非常有用。
如果您的查询确实是这种形式:
WHERE ISNULL(a.ColumnA, '') = ISNULL(b.ColumnA, '') AND
ISNULL(a.ColumnB, '') = ISNULL(b.ColumnB, '')
注意:将JOIN
条件放在WHERE
子句中没有任何意义。这些条件可能应该放在ON
子句中。
您可能只想用空字符串替换NULL
值:
update t
set columnA = coalesce(columnA, ''),
columnB = coalesce(columnB, '')
where columnA is null or columnB is null;
这将使索引的使用更加容易。
然后,您提到对varchar(800)
的限制。不存在这样的限制。较大的字符串值存储在辅助页面上。实际上,这在documentation中进行了解释:
行不能跨越页面,但是行的某些部分可能会移开 该行的页面,以便该行实际上可以很大。最大值 单个行中包含的数据量和开销量 页为8,060字节(8 KB)。但是,这不包括数据 存储在“文本/图像”页面类型中。
对于包含varchar,nvarchar, varbinary或sql_variant列。当所有的总行大小 表中的固定和可变列超过了8,060字节 限制,SQL Server动态移动一个或多个可变长度 从ROW_OVERFLOW_DATA分配单元中的页面开始的列 宽度最大的列。
因此,您可以减小列的大小,使索引更实用。