Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/25.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 server 使用OR的这些T-SQL查询之间有什么区别?_Sql Server_Sql Server 2008_Database Performance_Sql Execution Plan - Fatal编程技术网

Sql server 使用OR的这些T-SQL查询之间有什么区别?

Sql server 使用OR的这些T-SQL查询之间有什么区别?,sql-server,sql-server-2008,database-performance,sql-execution-plan,Sql Server,Sql Server 2008,Database Performance,Sql Execution Plan,我使用MicrosoftSQLServer2008SP1,x64。我有两个查询做相同的事情,或者我认为是这样,但是它们有完全不同的查询计划和性能 问题1: SELECT c_pk FROM table_c WHERE c_b_id IN (SELECT b_id FROM table_b WHERE b_z = 1) OR c_a_id IN (SELECT a_id FROM table_a WHERE a_z = 1) 问题2: SELECT c_pk FROM table_c LE

我使用MicrosoftSQLServer2008SP1,x64。我有两个查询做相同的事情,或者我认为是这样,但是它们有完全不同的查询计划和性能

问题1:

SELECT c_pk
FROM table_c
WHERE c_b_id IN (SELECT b_id FROM table_b WHERE b_z = 1)
  OR  c_a_id IN (SELECT a_id FROM table_a WHERE a_z = 1)
问题2:

SELECT c_pk
FROM table_c
LEFT JOIN (SELECT b_id FROM table_b WHERE b_z = 1) AS b ON c_b_id = b_id
LEFT JOIN (SELECT a_id FROM table_a WHERE a_z = 1) AS a ON c_a_id = a_id
WHERE b_id IS NOT NULL
  OR  a_id IS NOT NULL
查询1的速度和我预期的一样快,而查询2的速度非常慢。看起来很不一样

我希望查询2和查询1一样快。我有使用查询2的软件,我无法将其更改为查询1。我可以更改数据库

一些问题:

为什么查询计划不同? 我能否以某种方式教SQL Server查询2等于查询1? 所有表在所有列上都有群集主键和适当的索引:

CREATE TABLE table_a (
  a_pk   int NOT NULL PRIMARY KEY,
  a_id   int NOT NULL UNIQUE,
  a_z    int
)
GO
CREATE INDEX IX_table_a_z ON table_a (a_z)
GO

CREATE TABLE table_b (
  b_pk   int NOT NULL PRIMARY KEY,
  b_id   int NOT NULL UNIQUE,
  b_z    int
)
GO
CREATE INDEX IX_table_b_z ON table_b (b_z)
GO

CREATE TABLE table_c (
  c_pk   int NOT NULL PRIMARY KEY,
  c_a_id int,
  c_b_id int
)
GO
CREATE INDEX IX_table_c_a_id ON table_c (c_a_id)
GO
CREATE INDEX IX_table_c_b_id ON table_c (c_b_id)
GO
表格在最初填写后不进行修改。我是唯一质疑他们的人。它们包含数百万条记录表a:5M、表b:4M、表c:12M,但仅使用1%即可得出类似结果

编辑:我尝试为c_a_id和c_b_id添加外键,但这只会使查询1变慢


我希望有人能看一下,并解释一下两者的区别。

让我说,通过设计,Join的速度较慢。第一个查询使用可缓存的子查询来过滤记录,这样它将生成更少的数据,并减少对每个表的访问

你读过这些吗:


我的意思是,在数据库中使用,可以做更好的优化,比如删除重复项、在第一次匹配时停止以及类似的优化,这些都是来自学校的记忆,所以我相信它会做得更好。所以我想问题不在于为什么QP不同,而在于优化的深度有多聪明。

你在比较非等价查询,你也在以非常不寻常的方式使用左连接。 通常,如果您打算选择表_c中的所有条目,并且这些条目在表_a或表_b中有链接记录,则应使用exists语句:

SELECT c_pk 
FROM table_c 
WHERE  Exists( 
 SELECT 1
 FROM table_b 
 WHERE b_z = 1 and c_b_id = b_id 
) OR  Exists( 
 SELECT 1 
 FROM table_a 
 WHERE a_z = 1 and c_a_id = a_id
) 

既然不能更改查询,至少可以改进查询的环境

突出显示您的查询,在SSMS中右键单击它并选择分析 在数据库引擎优化顾问中查询。 运行分析以确定是否需要任何其他索引或 建立统计数据。 听从SQL Server的建议。
这样做的动机是什么?IN/EXISTS通常比外部联接更有效。。。SQL Server中为NULL,第一个查询对我来说似乎更清楚,那么为什么不直接使用第一个查询呢?@Martin我有一个使用查询2的软件,我无法改变这一点,因为一般来说,查询不同,连接可以产生重复行,而半连接不会。虽然我还没有检查是否有任何约束阻止这种情况发生。@Martin a_id和b_id是唯一的,因此连接不会重复行。我99%相信,在这种情况下,它们的语义似乎是相同的。但这并不意味着QO有必要的转换规则来将一个转换为另一个。通常,查询的编写方式会影响计划。您是否尝试过在带有USE plan提示的查询中使用计划quide,以尝试从第一个quide中获取第二个quide来使用该计划?IN是半联接。不确定您所说的可缓存子查询是什么意思。SQL Server在优化联接和子查询方面非常出色,并且将使用任何最快的查找。但在这种情况下不是这样。我理解索引,我不认为你的链接添加了任何相关内容。添加了一些我的意思的解释。如果你发布代码、XML或数据示例,请在文本编辑器中突出显示这些行,然后单击编辑器工具栏上的“代码示例”按钮{},以很好地格式化和语法突出显示它!我在SSMS中没有看到任何调优顾问。估计的执行计划没有显示任何缺失的索引。所有的栏目都已经被编入索引了,你认为还有什么需要补充的吗?@MicheldeRuiter-我怀疑你还有什么可以补充的。您需要重新编写查询,或者体验性能。在这种情况下,SQL Server似乎无法将OR转换为UNION,因此它正在处理表c中的所有行,并将其连接到其他两个表上,然后在最后执行筛选。您可能有免费版本,但该版本不可用或未安装。