【问题标题】:Table Valued Constructor Maximum rows limit in Select表值构造函数选择中的最大行数限制
【发布时间】:2017-03-20 12:44:10
【问题描述】:

我有一个Table Valued Constructor,通过它正在选择1 million 记录。它将用于update 另一个表。

SELECT *
FROM   (VALUES (100,200,300),
               (100,200,300),
               (100,200,300),
               (100,200,300),
               .....
               ..... --1 million records
               (100,200,300)) tc (proj_d, period_sid, val) 

这是我的原始查询:https://www.dropbox.com/s/ezomt80hsh36gws/TVC.txt?dl=0#

当我执行上述select 时,它只是显示 Query completed with errors 并显示任何错误消息。

更新: 尝试使用TRY/CATCH 块捕获错误消息或错误号,但没有使用仍然与上一张图片相同的错误

BEGIN try
    SELECT *
    FROM   (VALUES (100,200,300),
                    (100,200,300),
                    (100,200,300),
                    (100,200,300),
                    .....
                    ..... --1 million records
                    (100,200,300)) tc (proj_d, period_sid, val) 
END try

BEGIN catch
    SELECT Error_number(),
           Error_message()
END catch 

为什么它不执行是Select 中的 Table Valed 构造函数有任何限制。我知道Insert1000,但我在这里选择。

【问题讨论】:

  • 所有文字值都需要编译到执行计划中。在看到错误之前编译需要多长时间?
  • @MartinSmith - 总是少于 5 秒
  • 我已经尝试过了,八分钟后它仍在挣扎,没有结果或错误(尚未)DECLARE @SQL NVARCHAR(MAX) = '(100,200,300),' ; SELECT @SQL = 'SELECT * FROM (VALUES ' + REPLICATE(@SQL,1000000) + '(100,200,300)) tc (proj_d, period_sid, val)';EXEC(@SQL)
  • 我让它运行了 28 分钟然后杀死了它。可能它正在做这样的事情stackoverflow.com/questions/8635818/…

标签: sql sql-server sql-server-2012 bulkupdate


【解决方案1】:

没有相关的硬编码限制(65,536 * 4KB 的网络数据包大小为 268 MB,而您的脚本长度远不及此),但不建议对大量行使用此方法。

您看到的错误是由客户端工具而非 SQL Server 引发的。如果你在动态SQL编译中构造SQL String至少能够启动成功

DECLARE @SQL NVARCHAR(MAX) = '(100,200,300),
';

SELECT @SQL = 'SELECT * FROM (VALUES ' + REPLICATE(@SQL, 1000000) + '
(100,200,300)) tc (proj_d, period_sid, val)';

SELECT @SQL AS [processing-instruction(x)]
FOR XML PATH('')

SELECT DATALENGTH(@SQL) / 1048576.0 AS [Length in MB] --30.517705917

EXEC(@SQL);

虽然我在大约 30 分钟的编译时间后杀死了上述内容,但它仍然没有产生一行。文字值需要作为常量表存储在计划本身中,SQL Server 也花费了a lot of time 来尝试派生关于它们的属性。

SSMS 是一个 32 位应用程序,在解析批处理时会引发 std::bad_alloc 异常

它尝试将元素推送到已达到容量的 Token 向量上,但由于没有足够大的连续内存区域,它尝试调整大小失败。因此,该声明甚至从未到达服务器。

向量容量每次增长50%(即关注the sequence here)。向量需要增长到的容量取决于代码的布局方式。

以下需要从 19 个容量增加到 28 个。

SELECT * FROM 
(VALUES 
(100,200,300),
(100,200,300),
(100,200,300),
(100,200,300),
(100,200,300),
(100,200,300)) tc (proj_d, period_sid, val)

而下面只需要2的大小

SELECT * FROM (VALUES (100,200,300),(100,200,300),(100,200,300),(100,200,300),(100,200,300),(100,200,300)) tc (proj_d, period_sid, val)

以下需要> 63和

SELECT *
FROM   (VALUES 
      (100,
       200,
       300),
      (100,
       200,
       300),
      (100,
       200,
       300),
      (100,
       200,
       300),
      (100,
       200,
       300),
      (100,
       200,
       300)
       ) tc (proj_d, period_sid, val) 

对于像案例 1 那样布局的一百万行,向量容量需要增长到 3,543,306。

您可能会发现以下任何一项都可以让客户端解析成功。

  1. 减少换行数。
  2. 重启 SSMS,希望在地址空间碎片较少的情况下,对大块连续内存的请求成功。

但是,即使您确实成功地将其发送到服务器,它也只会在生成执行计划期间终止服务器,如上所述。

使用导入导出向导加载表格会好得多。如果您必须在 TSQL 中执行此操作,您会发现将其分成更小的批次和/或使用另一种方法(例如分解 XML)将比表值构造函数执行得更好。例如,在我的机器上执行以下操作需要 13 秒(尽管如果使用 SSMS,您仍然可能需要分成多个批次,而不是粘贴大量 XML 字符串文字)。

DECLARE @S NVARCHAR(MAX) = '<x proj_d="100" period_sid="200" val="300" />
' ; 

DECLARE @Xml XML = REPLICATE(@S,1000000);

SELECT 
    x.value('@proj_d','int'),
    x.value('@period_sid','int'),
    x.value('@val','int')
FROM @Xml.nodes('/x') c(x)

【讨论】:

    【解决方案2】:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-03-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多