查询在一个数据集中运行缓慢,但在另一个更大的数据集中运行得更快;微软服务器;不同的执行计划。为什么?

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 个数据集之间的执行计划差异

  1. "Actual number of Rows" & "Number of executions" 在较慢的数据集中是天文数字更高的
  2. 快的还有一个节点"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" 有数千条记录。感谢所有在这里提供帮助的人。