查询在一个数据集中运行缓慢,但在另一个更大的数据集中运行得更快;微软服务器;不同的执行计划。为什么?
Query runs slow in one dataset, but faster in another bigger dataset; MSSQL server; Different execution plan. Why?
这里是查询:
select nd1.ansos_id
from nursdate nd1
where nd1.division_id = 2
and nd1.unit_id = 19
and nd1.nursdate_start_date =
(select min(nd2.nursdate_start_date)
from nursdate nd2
where nd2.ansos_id = nd1.ansos_id
and nd2.nursdate_start_date >= all
(select nd3.nursdate_start_date
from nursdate nd3
where nd3.ansos_id = nd1.ANSOS_ID
and nd3.nursdate_start_date <= '2017-08-13 00:00:00'))
以下两个数据集均成立
- 统计数据是最新的;
- 索引碎片整理
- 两个数据集的常规属性相同:例如:整理;
- 而且这两个数据集的数据量也差不多。其实越快的数据越多
现在在 1 个数据集中 运行 需要大约 8 秒,但在另一个数据集中 <1 秒。
这是 2 个数据集之间的执行计划差异
- "Actual number of Rows" & "Number of executions" 在较慢的数据集中是天文数字更高的
- 快的还有一个节点"Index Spool"
屏幕截图 #1:同一查询,一个数据集中的执行计划缓慢
屏幕截图 #2:相同的查询,另一个数据集中的快速执行计划
如何解决这个问题?我该怎么做才能在第一个数据集中快速达到 运行?
谢谢!
[编辑] 较慢的执行计划:(注意整个 "nursdate" table 只有 99K 行)
https://www.brentozar.com/pastetheplan/?id=r1ZFFuNt-
更快的执行计划:(注意整个 "nursdate" table 有 333K 行。不知何故更快)
https://www.brentozar.com/pastetheplan/?id=rJYMc_EKb
[编辑] 这是关于数据量的一些信息。 "mmt" 上的数据较少,但 运行 较慢
--mmt cnt: 99347
select count(*)
from mmt_sqa_v60.mmtsqav60.nursdate nd1
--heo cnt: 333275
select count(*)
from heo_sqa_v60_2k12.heosqav602k12.nursdate nd1
--mmt cnt: 2403
select count(*)
from mmt_sqa_v60.mmtsqav60.nursdate nd1
where nd1.division_id = 2
and nd1.unit_id = 19
and nd1.nursdate_start_date <= '2017-08-13 00:00:00'
--heo cnt: 5537
select count(*)
from heo_sqa_v60_2k12.heosqav602k12.nursdate nd1
where nd1.division_id = 1
and nd1.unit_id = 20
and nd1.nursdate_start_date <= '2017-08-13 00:00:00'
与您的问题无关,但您的查询有一些问题。我认为您的查询功能是查找 ansos_id
之前的任何记录 @date
如果我错了请纠正我。
最深层次将 ansos_id
的所有日期都放在 @date
之前
select nd3.nursdate_start_date
from nursdate nd3
where nd3.ansos_id = nd1.ANSOS_ID
and nd3.nursdate_start_date <= '2017-08-13 00:00:00')
然后将之前的查询与所有这些日期进行比较。
and nd2.nursdate_start_date >= all ( ...)
这是非常低效的,因为唯一大于或等于所有日期的日期是 MAX(date)
然后你 (select min(nd2.nursdate_start_date)
当我已经解释过只有一个日期 >= to all
我会说您的查询应该替换为 return 每个 ansos_id
:
@date 之前的最后一条记录
WITH cte as (
select nd1.ansos_id, nursdate_start_date,
RANK() OVER (PARTITION BY ansos_id
ORDER BY nursdate_start_date DESC) as rn
from nursdate nd1
where nd1.division_id = 2
and nd1.unit_id = 19
and nd1.nursdate_start_date <= '2017-08-13 00:00:00'
)
SELECT *
FROM cte
WHERE rn = 1
谜团解开了。这是一个数据问题。这是 "execution plan" 的高数字的来源:
select count(*)
from mmtsqav60.NURSDATE ndArea
left outer join mmtsqav60.NURSDATE ndRelated on ndRelated.ANSOS_ID =
ndArea.ANSOS_ID
where ndArea.DIVISION_ID=2 and ndArea.UNIT_ID=19;
结果是 4157613,这正是执行计划所说的索引在 nd2 和 nd3 上返回的行数。因为,从本质上讲,上述逻辑是 WSM 中的 nursdate 查询要求数据库服务器执行的操作——查找某个区域的所有记录,然后针对每个此类记录查找该 ansos_id 的所有记录。
数据对我们来说是不切实际的数据,因为一个 "ansos_id" 有数千条记录。感谢所有在这里提供帮助的人。
这里是查询:
select nd1.ansos_id
from nursdate nd1
where nd1.division_id = 2
and nd1.unit_id = 19
and nd1.nursdate_start_date =
(select min(nd2.nursdate_start_date)
from nursdate nd2
where nd2.ansos_id = nd1.ansos_id
and nd2.nursdate_start_date >= all
(select nd3.nursdate_start_date
from nursdate nd3
where nd3.ansos_id = nd1.ANSOS_ID
and nd3.nursdate_start_date <= '2017-08-13 00:00:00'))
以下两个数据集均成立
- 统计数据是最新的;
- 索引碎片整理
- 两个数据集的常规属性相同:例如:整理;
- 而且这两个数据集的数据量也差不多。其实越快的数据越多
现在在 1 个数据集中 运行 需要大约 8 秒,但在另一个数据集中 <1 秒。 这是 2 个数据集之间的执行计划差异
- "Actual number of Rows" & "Number of executions" 在较慢的数据集中是天文数字更高的
- 快的还有一个节点"Index Spool"
屏幕截图 #1:同一查询,一个数据集中的执行计划缓慢
屏幕截图 #2:相同的查询,另一个数据集中的快速执行计划
如何解决这个问题?我该怎么做才能在第一个数据集中快速达到 运行? 谢谢!
[编辑] 较慢的执行计划:(注意整个 "nursdate" table 只有 99K 行) https://www.brentozar.com/pastetheplan/?id=r1ZFFuNt-
更快的执行计划:(注意整个 "nursdate" table 有 333K 行。不知何故更快) https://www.brentozar.com/pastetheplan/?id=rJYMc_EKb
[编辑] 这是关于数据量的一些信息。 "mmt" 上的数据较少,但 运行 较慢
--mmt cnt: 99347
select count(*)
from mmt_sqa_v60.mmtsqav60.nursdate nd1
--heo cnt: 333275
select count(*)
from heo_sqa_v60_2k12.heosqav602k12.nursdate nd1
--mmt cnt: 2403
select count(*)
from mmt_sqa_v60.mmtsqav60.nursdate nd1
where nd1.division_id = 2
and nd1.unit_id = 19
and nd1.nursdate_start_date <= '2017-08-13 00:00:00'
--heo cnt: 5537
select count(*)
from heo_sqa_v60_2k12.heosqav602k12.nursdate nd1
where nd1.division_id = 1
and nd1.unit_id = 20
and nd1.nursdate_start_date <= '2017-08-13 00:00:00'
与您的问题无关,但您的查询有一些问题。我认为您的查询功能是查找 ansos_id
之前的任何记录 @date
如果我错了请纠正我。
最深层次将 ansos_id
的所有日期都放在 @date
select nd3.nursdate_start_date
from nursdate nd3
where nd3.ansos_id = nd1.ANSOS_ID
and nd3.nursdate_start_date <= '2017-08-13 00:00:00')
然后将之前的查询与所有这些日期进行比较。
and nd2.nursdate_start_date >= all ( ...)
这是非常低效的,因为唯一大于或等于所有日期的日期是 MAX(date)
然后你 (select min(nd2.nursdate_start_date)
当我已经解释过只有一个日期 >= to all
我会说您的查询应该替换为 return 每个 ansos_id
:
WITH cte as (
select nd1.ansos_id, nursdate_start_date,
RANK() OVER (PARTITION BY ansos_id
ORDER BY nursdate_start_date DESC) as rn
from nursdate nd1
where nd1.division_id = 2
and nd1.unit_id = 19
and nd1.nursdate_start_date <= '2017-08-13 00:00:00'
)
SELECT *
FROM cte
WHERE rn = 1
谜团解开了。这是一个数据问题。这是 "execution plan" 的高数字的来源:
select count(*)
from mmtsqav60.NURSDATE ndArea
left outer join mmtsqav60.NURSDATE ndRelated on ndRelated.ANSOS_ID =
ndArea.ANSOS_ID
where ndArea.DIVISION_ID=2 and ndArea.UNIT_ID=19;
结果是 4157613,这正是执行计划所说的索引在 nd2 和 nd3 上返回的行数。因为,从本质上讲,上述逻辑是 WSM 中的 nursdate 查询要求数据库服务器执行的操作——查找某个区域的所有记录,然后针对每个此类记录查找该 ansos_id 的所有记录。 数据对我们来说是不切实际的数据,因为一个 "ansos_id" 有数千条记录。感谢所有在这里提供帮助的人。