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

Reduce Hash Match Cost in sql code

我有两个 table,我发现第二个 table 中存在但第一个 table 中不存在的缺失值。

下面是我的 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);

正在解释我的代码...

我有两个 table,一个用于患者就诊,另一个用于就诊查询。我在查找 table.

时有 10 到 70 位患者就诊

一些患者错过了定期就诊。假设一个病人来了 10、20、30、60 和 70 次就诊。那么 40 和 50 将在那里错过就诊。

我想return错过就诊的患者。因此,我将患者数据的患者和访问作为查询 A,将查找 table 中的数据作为查询 B。然后我从查询 A 中不存在的查找 table 进行访问。这将给出我错过了访问。

代码运行良好,我想优化代码。查看执行计划时,发现Hash Match占整体执行成本的46%

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

有没有办法优化这段代码,使性能更好?

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

已更新

我找到了哈希匹配花费更多成本的原因。这是由于

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

按照用户的建议,我创建了约束并修改了代码。

我在患者就诊时创建了覆盖索引 table 作为包含列的就诊,并对成本进行了一些更改。哈希匹配从 46% 降低到 20.5%,但是排序操作的成本从 26% 降低到 37%。但总成本下降到 41%

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

  • 您的表似乎没有规范化。 VisitlookupPatientVisit 表中都有 VisitName

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

  • 您正在使用 float 类型而不是某种整数类型来标识实体的字段。

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

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

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

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 反映:

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