2010-07-06 87 views
2

以下查询的执行效果不佳,因为P4FileReleases中的650万条记录完全非聚簇索引扫描,后面是散列连接。我正在寻找优化程序对搜索进行扫描的可能原因。摆脱完整索引扫描

SELECT p4f.FileReleaseID 
    FROM P4FileReleases p4f 
    INNER JOIN AnalyzedFileView af 
     ON p4f.FileRelease = (af.path+'#'+cast(af.revision as varchar)) 
    WHERE (af.tracked_change_id = 1) 

从我所知道的,我看不出有任何理由优化挑P4FileReleases的扫描。 WHERE子句将正确数据集的大小限制为大约1K条记录,优化器应该知道它(参见下面的直方图)。

如果事实上,如果我将视图数据放入一个堆表(与索引视图的结构相同),那么查询将在较大的表上执行索引查找,而不是一个内部联接循环哈希连接(总成本从145下降到1左右)。

关于什么可能会抛出优化器的想法?

详情。 Sql Server 2008(v。10.0.2757.0)。

P4FileReleases表 存放650万条记录

CREATE TABLE [dbo].[P4FileReleases](
    [FileReleaseID] [int] IDENTITY(1,1) NOT NULL, 
    [FileRelease] [varchar](254) NOT NULL, 
    -- 5 more fields 
CONSTRAINT [CIX_P4FileReleases_FileReleaseID_PK] PRIMARY KEY CLUSTERED 
(
    [FileReleaseID] ASC 
), 
CONSTRAINT [NCIX_P4FileReleases_FileRelease] UNIQUE NONCLUSTERED 
(
    [FileRelease] ASC 
) 

AnalyzedFileView 是启用并且最​​新的统计数据的索引视图。

它有四列:

key int (int, PK) - clustered index 
    tracked_change_id (int, FK) - non-unique, non-clustered index (covering 'path', 'revision') 
    path (nvarchar(1024), null) 
    revision (smallint, null) 

tracked_change_id直方图:

1 0 1222 0 1 
4 0 787  0 1 
8 0 2754 0 1 
12 0 254  0 1 
13 0 34  0 1 

查询计划

|--Parallelism(Gather Streams) 
     |--Hash Match(Inner Join, HASH:([Expr1011])=([Expr1010]), RESIDUAL:([Expr1010]=[Expr1011])) 
      |--Bitmap(HASH:([Expr1011]), DEFINE:([Bitmap1015])) 
      | |--Parallelism(Repartition Streams, Hash Partitioning, PARTITION COLUMNS:([Expr1011])) 
      |   |--Compute Scalar(DEFINE:([Expr1011]=([qpsitools].[dbo].[analyzed_file_view].[path]+N'#')+CONVERT_IMPLICIT(nvarchar(30),CONVERT(varchar(30),[qpsitools].[dbo].[analyzed_file_view].[revision],0),0))) 
      |    |--Index Seek(OBJECT:([qpsitools].[dbo].[analyzed_file_view].[tracked_change_id]), SEEK:([qpsitools].[dbo].[analyzed_file_view].[tracked_change_id]=(1)) ORDERED FORWARD) 
      |--Parallelism(Repartition Streams, Hash Partitioning, PARTITION COLUMNS:([Expr1010]), WHERE:(PROBE([Bitmap1015],[Expr1010]))) 
       |--Compute Scalar(DEFINE:([Expr1010]=CONVERT_IMPLICIT(nvarchar(254),[Blueprint].[dbo].[P4FileReleases].[FileRelease] as [p4f].[FileRelease],0))) 
         |--Index Scan(OBJECT:([Blueprint].[dbo].[P4FileReleases].[NCIX_P4FileReleases_FileRelease] AS [p4f])) 

回答

5

您正在与nvarchar列(af.path)接合varchar列p4f.FileRelease WHERE被应用。由于数据类型不匹配,SQL必须将其类型转换为另一种类型(当然,它不能从nvarchar转换为varchar)。在将af.path转换为nvarchar时,它失去了使用索引查找/过滤这些值的能力,导致需要扫描并转换所有可能的行。

最好的解决方案是将数据存储为匹配数据类型(将列p4f.FileRelase更改为nvarchar,或将af.path更改为varchar)。由于没有人可以修改现有的数据库结构,因此可以明确施放af。查询中varchar的路径。测试它并查看...虽然当然,如果数据确实需要双字节格式,则无法执行此操作。

+0

即使将它作为匹配类型存储,他将两个字段与#inbetween拼接在一起的事实也会强制扫描不会吗? – 2010-07-06 18:42:27

+1

太棒了!看起来像varchar vs nvarchar是问题。谢谢! – 2010-07-06 19:14:18

+0

@Mike M,“... WHERE ColName = @Variable”和“... WHERE ColName = @Variable + @Variable”之间的SQL *与*之间几乎没有什么区别。它需要你产生的任何价值,并在表格中查找它。 – 2010-07-06 20:34:56

2

你的问题不是在WHERE但JOIN,你得到W上的JOIN上的隐式转换和扫描这里条件你得到一个SEEK

ON p4f.FileRelease = (af.path+'#'+cast(af.revision as varchar)) 

并行也可能是一个问题,尝试添加MAXDOP = 1

是你的统计数据是最新的?是否存在过度分散?

+0

是的,这就是我所说的:我正在寻找关于加入的位置和扫描。我想明白为什么。我实际上使用MAXDOP = 1,我在这里省略了它。所以我所包含的所有数据都是用于非并行处理的。 – 2010-07-06 18:51:24

+2

优化器不知道af.path +'#'+ cast(af.revision as varchar)的值是否必须扫描整个表格 – SQLMenace 2010-07-06 19:04:47

0

尝试将“af.tracked_change_id = 1”移动到join子句中。

INNER JOIN AnalyzedFileView af 
ON p4f.FileRelease = (af.path+'#'+cast(af.revision as varchar)) 
AND af.tracked_change_id = 1 

后的INNER JOIN

+0

这样做没有影响。无论如何,优化器不应该足够聪明地重新排列吗? – 2010-07-06 18:55:22

0

菲利普凯利发现了这个问题。这是P4FileReleases中的varchar和AnalyzedFileView中的nvarchar之间的数据类型不匹配。