Sql server SQL Server 2005性能:WHERE in语句中的独立表或完整表
我们有两张桌子: 文档:id、标题、文档类型、显示id DocumentType:id,name 关系:DocumentType有许多文档。Document.Document\u type\u id=DocumentType.id 我们希望检索一个给定ShowOn_Id的所有文档类型的列表 我们看到两种可能性:Sql server SQL Server 2005性能:WHERE in语句中的独立表或完整表,sql-server,database,performance,Sql Server,Database,Performance,我们有两张桌子: 文档:id、标题、文档类型、显示id DocumentType:id,name 关系:DocumentType有许多文档。Document.Document\u type\u id=DocumentType.id 我们希望检索一个给定ShowOn_Id的所有文档类型的列表 我们看到两种可能性: SELECT DocumentType.* FROM DocumentType WHERE DocumentType.id IN ( SELECT DISTINCT Docume
SELECT DocumentType.*
FROM DocumentType
WHERE DocumentType.id IN (
SELECT DISTINCT Document.document_type_id FROM Document WHERE showon_id = 42
);
SELECT DocumentType.*
FROM DocumentType
WHERE DocumentType.id IN (
SELECT Document.document_type_id FROM Document WHERE showon_id = 42
);
我们的问题是:何时和是否使用DISTINCT来获取较小的记录集,比检索整个表和在表中遍历到第一个匹配项的IN语句更好。我们猜它就是这样做的-
对于不同的数据库,这是不同的吗?有共同的答案吗
还是有更好的方法?我们在.NET land中您可以使用连接:
SELECT DISTINCT DocumentType.*
FROM DocumentType
INNER JOIN Document
ON DocumentType.id=Document.document_type_id
WHERE Document.showon_id = 42
我认为这是最好的方法。从我的观点来看,它在SQL Server内部不应该有任何区别,但谁知道这是如何实现的
可以这样想:要返回结果集,服务器需要进入Document表并检索所有Document_type_id,其中shown_id=42。在检索文档_type _id的过程中(例如通过索引查找),会将其放入哈希表中。此过程完成后,哈希表仍将包含不同的值。之后,查询执行进入Document_Type表,扫描主键并探测哈希表。请注意,这取决于,例如,当文档表中的预期行数比文档类型低时,不使用哈希表可能更有效,但通常您会得到与刚才建议的查询wmasm相同的查询计划。使用EXISTS。它有时速度更快,但在我看来,它比一个DISTINCT和JOIN更具可读性。只是为了好玩,请回复这个查询的查询计划和上面的连接,看看是否有什么不同,他们可能会优化到相同的计划。如果它们相同,我建议使用EXISTS,因为它更接近纯语言描述,而不是JOIN,因为您不需要来自文档等的任何数据
SELECT whatever
FROM DocumentType dt
WHERE EXISTS( SELECT *
FROM Document
WHERE dt.id = document_type_id
AND showon_id = 42)
要获取查询计划参考,请执行以下操作:
后续行动:
我已经启用了查询计划,并测试了迄今为止出现的四种不同查询:
选择DocumentType.*从DocumentType中选择DocumentType.id,从showon\u id=42的文档中选择DISTINCT Document.Document\u type\u id
选择DocumentType.*从DocumentType中选择Document.Document\u type\u id从shown\u id=42的文档中选择Document.Document\u type\u id
从DocumentType.id=Document.Document\u type\u id其中Document.shown\u id=42的DocumentType内部连接文档中选择DISTINCT DocumentType.*
选择DocumentType.*从存在的DocumentType中选择*从DocumentType.id=Document.Document\u type\u id和showon\u id=42的文档
所有四个查询的查询计划都是相同的:
|--Hash Match(Right Semi Join, HASH:([Document].[document_type_id])=([DocumentType].[Id]))
|--Hash Match(Inner Join, HASH:([Document].[Title], [Uniq1005])=([Document].[Title], [Uniq1005]), RESIDUAL:([Document].[Title] as [Document].[Title] = [Document].[Title] as [Document].[Title] AND [Uniq1005] = [Uniq1005]))
| |--Index Seek(OBJECT:([Document].[IX_Document_3] AS [Document]), SEEK:([Document].[showon_id]=(1)) ORDERED FORWARD)
| |--Index Scan(OBJECT:([Document].[IX_Document_1] AS [Document]))
|--Table Scan(OBJECT:([DocumentType] AS [DocumentType]))
我不确定每一行和每一个元素都意味着什么,但从性能的角度来看,如何构造这种问题的查询似乎并不重要 为了获得最佳性能,您应该使用:
SELECT DISTINCT dt.*
FROM
DocumentType dt
INNER JOIN Document d ON dt.id=d.document_type_id and d.showon_id = 42
联接在桥接多个表时非常有效,因为where子句中的嵌套查询需要执行单独的结果选择,该选择将过滤From子句结果。join语句也更具可读性
除了主键和外键关系之外,我还会在showon_id上添加索引
我的答案与wmasm的答案不同,只是将showon_id筛选器上移到内部联接。对于MS SQL 2k5,我认为解释器足够聪明,可以自动执行此操作,但您总是希望使用尽可能小的结果集。当将多个表连接在一起时,将过滤器提升到内部联接语句可以限制查询必须处理的行数。如果您这样做,您应该了解每行比较都会发生这种情况,因此最好将复杂的筛选器(如x='%a'或函数调用)留给Where子句,以便内部联接可以过滤掉不必要的比较。谢谢,这可能是解决此问题的最简单方法。。。这个查询也比IN子查询快吗?正如ligged78指出的,您也发现了,如果查询计划返回不同的东西,我会非常惊讶。毕竟,性能必须基于您的表/索引设计,而不是查询语法。是的,两个查询的结果集应该相同。所以问题是:服务器是否会自己过滤掉重复的值,过滤是否会对性能产生影响?如果是,使用DISTINCT时是否会以相同的方式进行过滤?->同样,您可以尝试测量所有类型查询的数据性能。有关工具,请参阅。
SELECT DISTINCT dt.*
FROM
DocumentType dt
INNER JOIN Document d ON dt.id=d.document_type_id and d.showon_id = 42