【问题标题】:Maximum size for a SQL Server Query? IN clause? Is there a Better Approach [duplicate]SQL Server 查询的最大大小? IN 子句?有没有更好的方法[重复]
【发布时间】:2010-12-24 14:15:48
【问题描述】:

可能重复:
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 子句?

【问题讨论】:

标签: sql sql-server tsql limits


【解决方案1】:

每批,65536 * Network Packet Size 是 4k 所以 256 MB

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

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

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

【讨论】:

    【解决方案2】:

    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 并不会完全发现统计信息太有用。)

    【讨论】:

    • 查看更新。感谢您的测试 +1
    • 不幸的是,这些查询会定期发生。所以我认为临时表的索引是不可能的。对于最大快速插入,主表将由 int 'addid' 索引(不会在 GUID 上索引)。这东西比我想象的要复杂。
    • 您正在冒着轻微过早优化的风险——您需要在工作负载的查询计划方面获得一些经过测试的硬数据,因为它很难建模。一旦您了解了各种方法的数字,您就可以做出选择,但是将 1k 行插入 SQL 临时表可以非常快速地完成,这实际上取决于驱动它的方式/什么。
    • 你不需要每次都创建 temptable。如果它是一个重要的业务逻辑,只需制作一个带有索引的静态表,批量插入 guid,然后加入。索引也会在短时间内有所帮助,因为 SQL 会存储知道如何使用数据的数据。
    【解决方案3】:

    每个 SQL 批处理必须适合 Batch Size Limit: 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 会达到 SO at about 10k values in the IN,但现在堆栈要深得多(因为 x64),所以它可以走得非常深。

    更新

    您已经找到了 Erland 关于将列表/数组传递给 SQL Server 的文章。在 SQL 2008 中,您还拥有 Table Valued Parameters,它允许您将整个 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;
    

    【讨论】:

    • "stack size":这是我不记得的错误
    • @gbn,我认为错误更多的是“堆栈溢出”,因此,我们找到了解决该问题的正确网站。
    【解决方案4】:

    你能把 GUID 加载到一个临时表中然后做一个

    ... WHERE var IN SELECT guid FROM #scratchtable
    

    【讨论】:

    • 如果您假设您每隔一两秒就会有这些查询。我想知道临时表会如何支撑。
    • 我们在我们的应用程序中广泛使用了这种技术,它似乎运行良好。 Tempdb 需要很大,我们对安装进行了一些调整——我不知道具体情况。 Tempdb 确实很忙。
    猜你喜欢
    • 2021-06-02
    • 1970-01-01
    • 1970-01-01
    • 2021-04-24
    • 2014-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多