如何避免密钥查找

时间:2015-12-26 04:02:13

标签: azure azure-sql-database clustered-index non-clustered-index

我的数据库需要将GUID作为其主键,因为它与多个脱机数据库同步,因此IDENTITY列不是一个选项,因为它会导致同步中的冲突。

由于GUID会导致高表碎片,因此我们选择在我们的所有表CREATEDDATETIME中添加另一列,这是一个时间戳,并使CREATEDDATETIME成为CLUSTERED索引,并且GUID列已成为非CLUSTERED索引。

问题是CREATEDDATETIME几乎不用于WHERE子句,因此几乎所有执行计划中的查询都在聚集索引CREATEDDATETIME上显示KEY LOOKUP以获取其数据。我想知道这两种方式中的一种是否可以改善这种性能:

  1. 对于所有非聚集索引,例如GUID列上的索引,我也是 INCLUDE CREATEDDATETIME专栏? OR;

  2. 我将每个非聚集索引作为我所在的复合键 确保聚集索引是其中的一部分,即GUID + CREATEDDATETIME

  3. 哪一个可能更好?

2 个答案:

答案 0 :(得分:2)

当您最终需要的信息在叶级别不可用时,会发生密钥查找,因此必须转到聚簇索引才能获取它。想象一下以下查询:

select a, b, c
from dbo.yourTable
where GUID = <some guid>;

如果索引中包含a,b和c列,则可以避免键查找。请注意,群集键在每个非聚集索引中自动为包含列(这是有道理的 - 它还能够如何进行键查找?)。因此,根据实际选择的内容添加列,我认为您会看到密钥查找从查询计划中消失。

答案 1 :(得分:1)

由于您在上面的注释中提到了SQL-Azure,因此可以肯定地说您必须测试不同的方法。您已列出2,可能还有其他人,具体取决于您的应用程序(数据,查询配置文件和索引覆盖率)。

您可能已经知道,碎片会影响从插入中选择的方式。因此,您的应用需求将决定您做出的选择。当您为查找进行优化时,您的插入内容可能会变得难以忍受。

逻辑碎片和物理碎片都可能影响选项1,而选项2看起来像是一个明显的开销,没有明确的优化条件(适合使用的计划)。 Azure手册中显示的计划优化技术可以为此提供帮助。

对于碎片测试,我使用了有人推荐的查询:

SELECT OBJECT_NAME (S.[object_id]) as ObjectName,
       I.name as IndexName,
       ROUND (S.avg_fragmentation_in_percent, 2) as FragPercent,
       S.page_count as PageCount,
       ROUND (S.avg_page_space_used_in_percent, 2) as PageDensity
FROM sys.dm_db_index_physical_stats 
     (DB_ID ('MyDatabase'), NULL, NULL, NULL, 'DETAILED') as S
CROSS APPLY sys.indexes as I
WHERE I.object_id=S.object_id
AND   I.index_id=S.index_id
AND   S.index_level = 0;