减少sql代码中的哈希匹配成本

时间:2015-11-23 06:21:36

标签: sql-server performance sql-server-2012 sql-execution-plan

我有两个表,我发现第二个表中存在缺失值,但第一个表中没有。

下面是我的sql代码。

SELECT DISTINCT A.Patient
   ,B.Visit
FROM ( SELECT Patient
           ,Visit
           ,VisitName
        FROM dbo.PatientVisit
     ) A
   ,( SELECT Visit
           ,VisitName
        FROM dbo.Visitlookup v1
    ) B
WHERE B.Visit NOT IN ( SELECT Visit
                        FROM dbo.PatientVisit p1
                        WHERE A.Patient = p1.Patient )
    AND B.Visit <> A.Visit
GROUP BY A.Patient
   ,B.Visit
HAVING B.Visit <> MAX(A.Visit);

解释我的代码......

我有两个表用于患者就诊,另一个用于访问查找。我在10岁到70岁之间有耐心的访问。

有些患者在常规时间表中错过了访问。假设患者来过10,20,30,60和70次访问。所以40和50将会错过访问。

我想找回错过就诊的病人。所以我将患者和访问的患者数据作为查询A,将查询表中的数据作为查询B.然后我从查询表中查询表中访问,这将给我错过的访问次数。

代码工作正常,我想优化代码。当我检查执行计划时,我发现Hash Match占总体执行成本的46%。

以下是我的执行计划截图。

Execution Plan

有没有办法优化此代码,以便性能更好?

我有sql fiddle中的架构和数据。

更新

我发现哈希匹配需要更多成本的原因。它的原因是

在以下情况下可能会弹出哈希匹配:

  • 参与join,union的表格上没有覆盖索引 或聚合操作。
  • 一张大桌子正在加入一张小桌子,Hash 在这些情况下,匹配有时被证明是非常有效的。

用户建议我创建约束并修改代码。

我在患者就诊表上创建了覆盖索引作为包含列,并对成本进行了一些更改。哈希匹配从46%降至20.5%,但排序操作的成本从26%降至37%。但整体成本降至41%

enter image description here

2 个答案:

答案 0 :(得分:1)

我认为您不需要对表dbo.PatientVisitdbo.Visitlookup进行子查询,cross join也可以由INNER JOIN替换。此外,您可以将NOT IN (SELECT FIELD FROM ... WHERE {Condition}))替换为NOT EXISTS (SELECT NULL FROM ... WHERE {Condition})

所以,我建议最终必须是这样的:

SELECT  A.Patient ,
        B.Visit ,
        MAX(A.Visit)
FROM    dbo.PatientVisit AS A
        INNER JOIN dbo.Visitlookup AS B ON NOT EXISTS ( SELECT    NULL
                                                  FROM      dbo.PatientVisit p1
                                                  WHERE     A.Patient = p1.Patient
                                                            AND B.Visit = p1.Visit )
                                     AND A.Visit <> B.Visit
GROUP BY A.Patient ,
        B.visit
HAVING  B.Visit <> MAX(A.Visit)

使用您的数据样本您将看不到差异,但如果您将多次增加数据集,您将看到此执行计划:

执行计划的SSMS反映:

SSMS Actual execution plan

SQL Sentry Plan Explorer执行计划的反映:

SQL Sentry Plan Explorer

答案 1 :(得分:0)

您在查询计划的一个块上花费44%并不一定意味着查询速度很慢。但是,正如我所注意到的,您还有其他一些可能影响查询速度的问题。

  • 您的表似乎没有正常化。您在VisitNameVisitlookup表中都有PatientVisit

  • 您的表缺少主键,因此缺少任何索引。如果添加一些约束,则查询计划看起来非常不同。请参阅http://sqlfiddle.com/#!6/bb4db/1/0

  • 您正在使用float类型而非某些整数类型来识别实体的字段。

  • 查询本身看起来很可疑。您确定前两个子查询需要是子查询吗?