Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/85.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 为什么子查询和联接如此缓慢_Sql_Sql Server_Join - Fatal编程技术网

Sql 为什么子查询和联接如此缓慢

Sql 为什么子查询和联接如此缓慢,sql,sql-server,join,Sql,Sql Server,Join,我需要从BUNDLES表中选择具有多个SAP\u STATE\u ID值之一的行。这些值取决于是否应导出相应的SAP状态 此查询运行速度非常快(SAP_STATE_ID字段上有索引)—— 但是。。。我希望动态获取ID列表,如下所示: SELECT b.* FROM BUNDLES b WHERE b.SAP_STATE_ID IN (SELECT s.SAP_STATE_ID FROM SAP_STATES s WHERE s.EXPORT_TO_SAP = 1) 哎哟,这个查询突然花了太

我需要从BUNDLES表中选择具有多个SAP\u STATE\u ID值之一的行。这些值取决于是否应导出相应的SAP状态

此查询运行速度非常快(SAP_STATE_ID字段上有索引)——

但是。。。我希望动态获取ID列表,如下所示:

SELECT b.* FROM BUNDLES b 
WHERE b.SAP_STATE_ID IN 
(SELECT s.SAP_STATE_ID FROM SAP_STATES s WHERE s.EXPORT_TO_SAP = 1)
哎哟,这个查询突然花了太多时间。我希望SQLServer首先运行子查询(它不依赖于主查询中的任何内容),然后像我的第一个示例一样运行整个查询。我尝试将其重写为使用联接而不是子查询:

SELECT b.* FROM BUNDLES b 
JOIN SAP_STATES s ON (s.SAP_STATE_ID = b.SAP_STATE_ID) 
WHERE s.EXPORT_TO_SAP = 1
但它也有同样糟糕的表现。它似乎正在为BUNDLES表的每一行运行子查询,或者类似的内容。我不太擅长阅读执行计划,但我试过了。它说81%的成本用于扫描BUNDLE的主键索引(我不知道为什么要这样做,有BUNDLE_ID字段定义为主键,但它根本没有出现在查询中…)

有人能解释为什么SQL server如此“愚蠢”吗?有没有一种方法可以在不需要提供SAP_STATE_id静态列表的情况下,以良好的性能实现我想要的目标

表和相关索引的脚本-

子查询版本的执行计划-

具有联接的版本的查询计划-


(由于某些原因,这两个计划看起来是一样的,都建议创建BUNDLES.SAP\u STATE\u ID index,它已经存在)

因为出于某些原因,访问mab.to时出现问题

我建议确保:

table        index
sap_states   (export_to_sap, sap_state_id )
bundles      (sap_state_id)

select
      b.*
   from 
      sap_states ss
         join bundles b
            on ss.sap_state_id = b.sap_state_id
   where 
      ss.export_to_sap = 1
当您使用表(临时表或物理表)时,SQL引擎会根据表生成统计信息,因此对表中的行数以及哪种执行方法是最好的都有非常清楚的了解。另一方面,计算表(子查询)没有针对它的统计信息

因此,虽然人类推断其中的行数似乎很简单,但“愚蠢”的SQL引擎却不知道这一切。现在,说到查询,
WHERE s.EXPORT\u to\u SAP=1
子句在这里产生了巨大的变化。聚集索引是在SAP_STATE_ID上排序和构建的,但是为了额外检查WHERE子句,它除了扫描整个表(在最终的数据集中)之外别无选择!我敢打赌,如果不是聚集索引,而是SAP_STATE_ID列上覆盖了EXPORT_TO_SAP字段的非聚集覆盖索引,那么它可能已经成功了。由于聚集索引扫描通常不利于性能,我建议您采用以下方法:

SELECT s.SAP_STATE_ID 
into #Sap_State
FROM SAP_STATES s WHERE s.EXPORT_TO_SAP = 1

SELECT b.* FROM BUNDLES b 
join #Sap_State a on a.sap_state_id = b.sap_state_id

我敢肯定你的统计数字已经过时了。如果您想让它尽快工作,我会将查询写为:

SELECT b.*
  FROM SAP_STATES s 
 INNER LOOP JOIN BUNDLES b 
    ON s.SAP_STATE_ID = b.SAP_STATE_ID
 WHERE s.EXPORT_TO_SAP = 1

这将强制在
SAP\u STATES
上进行嵌套循环连接,该循环在
bundle

上进行过滤。是否有SAP\u STATES的索引。SAP\u STATE\u ID?是,它实际上是一个主键子查询自己运行需要多长时间?使用索引定义发布架构可能会有所帮助。能否将查询计划保存为.sqlplan文件并与我们共享?我尝试使用联接重写查询(如问题中所述),但没有成功。您的查询只交换了bundles和sap_states表的顺序-我尝试了这一点,但结果保持不变。您是否在
bundles.sap_state_id
上创建了索引?此外,请使用联接发布查询的解释计划。是的,我认为这种方法可以提高性能。但在这种情况下,使用临时表对我来说有点奇怪。要100%清洁,在选择后还应该有DROP TABLE#Sap#U状态。所以我们把原来的一行改成了三行,这让我很不高兴。顺便说一句,为什么这个方法有效而其他方法无效?我不明白为什么临时表中的值比子查询结果产生的记录集中的值快。这仅仅是关于优化器在其他情况下没有建立正确的执行计划吗?编辑了我的答案并进行了解释。是的,这就成功了。我感到惭愧的是,我以前从未听说过这样的选择。我必须了解更多关于循环的事情。我认为创建适当的统计信息应该让优化器选择正确的连接类型,这样循环关键字在这里就不需要了,这是正确的吗。我非常确信,如果您在ShowPlan上运行查询,您将看到返回行的估计和有效数量会有很大的不同。通常,更新统计数据就足以解决问题。在某些情况下,您需要做更多的异国情调的事情,例如“为未知优化”,但我认为这里不需要这样做。
SELECT b.*
  FROM SAP_STATES s 
 INNER LOOP JOIN BUNDLES b 
    ON s.SAP_STATE_ID = b.SAP_STATE_ID
 WHERE s.EXPORT_TO_SAP = 1