尝试在设计不良的桌子上提高性能

时间:2018-07-04 00:39:19

标签: sql sql-server sql-server-2014

我有一张桌子,不幸的是,桌子是用有趣的方式设计的。它有30列,均为NVARCHAR(MAX)。它被设计为快速的“数据仓库样式”表,但是具有事务性。

一列是bit,称为IsPhysical。该表具有一个PK,仅涉及索引。所有这些NVARCHAR列都在WHERE子句中使用。桌子不大。在10万行到50万之间。

但是由于我们执行的查询类型很常见,

WHERE 
    ISNULL(a.ColumnA, '') = ISNULL(b.ColumnA, '') 
    AND ISNULL(a.ColumnB, '') = ISNULL(b.ColumnB, '')` 

其中ColumnAColumnB等的类型为NVARCHAR(MAX)

我们遇到了一些性能问题。

我们在WHERE子句中经常有两列是IsActiveIsPhysical。因此,我将对这些应用索引,以查看是否可以获得任何好处。

所以在此之前,我做了一个查询:

SELECT * 
FROM MyTable 
WHERE IsActive = 1

我发现奇怪的是:为什么执行计划针对该查询报告“聚集索引扫描”?该表在Id列上有一个聚集索引-UNIQUEIDENTIFIER。我不确定UNIQUEIDENTIFIER上的聚集索引的好处是什么,但这还需要研究。

读取表上的

99%的活动。因此,我希望将索引应用于其中的某些列,但由于它们是NVARCHAR(MAX)-该选项不可用。并且将它们更改为VARCHAR(800)将打破8000字节的行限制。

因此,尝试TRY帮助的唯一方法是为这些IsPhysicalIsActive列建立索引,并可能更改PK上的索引类型?但不确定为什么,在将索引添加到这些列之前,我得到了“聚集索引扫描”。

1 个答案:

答案 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分配单元中的页面开始的列   宽度最大的列。

因此,您可以减小列的大小,使索引更实用。