101

可能重复:
T-SQL WHERE col IN (...)

SQL Server 查询的最大大小是多少?(字符数)

IN 子句的最大大小?我想我看到 Oracle 有 1000 个项目的限制,但你可以通过 ANDing 2 个 IN 一起解决这个问题。SQL Server 中的类似问题?

更新 那么,如果我需要从另一个系统(非关系数据库)获取 1000 个 GUID 并对 SQL Server 执行“代码中的加入”,那么最好的方法是什么?是将 1000 个 GUID 的列表提交给 IN 子句? 或者还有其他更有效的技术吗?

我尚未对此进行测试,但我想知道是否可以将 GUID 作为 XML 文档提交。例如

<guids>
    <guid>809674df-1c22-46eb-bf9a-33dc78beb44a</guid>
    <guid>257f537f-9c6b-4f14-a90c-ee613b4287f3</guid>
</guids>

然后针对 Doc 和 Table 执行某种 XQuery JOIN。效率低于 1000 项 IN 子句?

4

4 回答 4

86

每个 SQL 批处理都必须符合批处理大小限制:65,536 * 网络数据包大小。

除此之外,您的查询受运行时条件的限制。它通常会用完堆栈大小,因为 x IN (a,b,c) 只不过是 x=a OR x=b OR x=c ,它创建类似于 x=a OR (x=b OR (x =c)),所以它在大量 OR 的情况下变得非常深。SQL 7 会在 IN 中以大约 10k 的值达到 SO ,但现在堆栈要深得多(因为 x64),所以它可以走得非常深。

更新

您已经找到了 Erland 关于将列表/数组传递给 SQL Server 的文章。使用 SQL 2008,您还可以使用表值参数,它允许您将整个 DataTable 作为单个表类型参数传递并加入它。

XML 和 XPath 是另一个可行的解决方案:

SELECT ...
FROM Table
JOIN (
   SELECT x.value(N'.',N'uniqueidentifier') as guid
   FROM @values.nodes(N'/guids/guid') t(x)) as guids
 ON Table.guid = guids.guid;
于 2009-12-08T21:01:47.620 回答
41

SQL Server 最大值公开http://msdn.microsoft.com/en-us/library/ms143432.aspx(这是 2008 版)

SQL 查询可以是 varchar(max),但显示为限制为 65,536 * 网络数据包大小,但即便如此,最有可能让您绊倒的是每个查询的 2100 个参数。如果 SQL 选择参数化 in 子句中的文字值,我想你会首先达到这个限制,但我还没有测试过。

编辑:测试它,即使在强制参数化的情况下它也能幸存下来——我进行了一个快速测试,并让它在 In 子句中使用 30k 个项目执行。(SQL Server 2005)

在 100k 项目中,花了一些时间然后丢弃:

消息 8623,级别 16,状态 1,第 1 行查询处理器用尽内部资源,无法生成查询计划。这是一个罕见的事件,仅适用于极其复杂的查询或引用大量表或分区的查询。请简化查询。如果您认为自己错误地收到了此消息,请联系客户支持服务以获取更多信息。

所以 30k 是可能的,但仅仅因为你能做到 - 并不意味着你应该:)

编辑:由于其他问题而继续。

50k 工作,但 60k 掉线了,所以顺便说一句,在我的测试台上的某个地方。

至于如何在不使用大 in 子句的情况下进行值的连接,我个人会创建一个临时表,将值插入到该临时表中,对其进行索引,然后在连接中使用它,给它最好的机会优化连接。(在临时表上生成索引将为它创建统计信息,这将有助于优化器作为一般规则,尽管 1000 个 GUID 不会完全发现统计信息太有用。)

于 2009-12-08T20:58:34.647 回答
14

每批,65536 * 网络数据包大小为 4k,即 256 MB

但是,IN 会在此之前停止,但并不精确。

您最终会出现内存错误,但我不记得确切的错误。无论如何,一个巨大的 IN 将是低效的。

编辑:Remus 提醒我:错误与“堆栈大小”有关

于 2009-12-08T20:56:46.450 回答
8

您可以将 GUID 加载到临时表中,然后执行

... WHERE var IN SELECT guid FROM #scratchtable
于 2009-12-08T21:14:20.340 回答