减少 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 上没有可用的覆盖索引
或聚合操作。
- 一个大 table 正在加入一个小得多的 table,哈希
在这些情况下,Match 有时被证明是非常有效的。
按照用户的建议,我创建了约束并修改了代码。
我在患者就诊时创建了覆盖索引 table 作为包含列的就诊,并对成本进行了一些更改。哈希匹配从 46% 降低到 20.5%,但是排序操作的成本从 26% 降低到 37%。但总成本下降到 41%
您在查询计划的一个块上花费了 44% 并不一定意味着查询很慢。但是,正如我所注意到的,您还有一些其他问题可能会影响任何查询速度。
您的表似乎没有规范化。 Visitlookup
和 PatientVisit
表中都有 VisitName
。
您的表缺少主键,因此缺少任何索引。如果添加一些约束,查询计划看起来会很不一样。见 http://sqlfiddle.com/#!6/bb4db/1/0.
您正在使用 float
类型而不是某种整数类型来标识实体的字段。
查询本身看起来很可疑。您确定前两个子查询需要是子查询吗?
我认为dbo.PatientVisit
和dbo.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 反映:
我有两个 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 上没有可用的覆盖索引 或聚合操作。
- 一个大 table 正在加入一个小得多的 table,哈希 在这些情况下,Match 有时被证明是非常有效的。
按照用户的建议,我创建了约束并修改了代码。
我在患者就诊时创建了覆盖索引 table 作为包含列的就诊,并对成本进行了一些更改。哈希匹配从 46% 降低到 20.5%,但是排序操作的成本从 26% 降低到 37%。但总成本下降到 41%
您在查询计划的一个块上花费了 44% 并不一定意味着查询很慢。但是,正如我所注意到的,您还有一些其他问题可能会影响任何查询速度。
您的表似乎没有规范化。
Visitlookup
和PatientVisit
表中都有VisitName
。您的表缺少主键,因此缺少任何索引。如果添加一些约束,查询计划看起来会很不一样。见 http://sqlfiddle.com/#!6/bb4db/1/0.
您正在使用
float
类型而不是某种整数类型来标识实体的字段。查询本身看起来很可疑。您确定前两个子查询需要是子查询吗?
我认为dbo.PatientVisit
和dbo.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 反映: