2

我们正在尝试设置一个游标来运行从同一个巨大表的两个“实例”之间的连接生成的记录(超过 150 M 记录)。

出现以下异常消息:

无法为数据库“tempdb”中的对象“dbo.SORT 临时运行存储:165282123350016”分配空间,因为“PRIMARY”文件组已满。通过删除不需要的文件、删除文件组中的对象、向文件组添加其他文件或为文件组中的现有文件设置自动增长来创建磁盘空间。

你们有谁知道这其中的原因吗?或者如何使下面的查询更有效率?

我发现它发生在DECLARE CURSOR和第一个之间的某个地方FETCH NEXT,但我还不知道它是否介于...

  • DECLARE CURSOROPEN

或之间

  • OPEN和第一个FETCH NEXT

更多细节: sql 语句如下所示:

DECLARE cData CURSOR LOCAL FORWARD_ONLY READ_ONLY
为了
  选择 ...
  从 HugeTable HT1 加入 HugeTable HT2 ..
  加入表 3 开 .. 加入表 4 开 .. 加入表 5 开 ..
  在哪里 ...
  由 HT1 订购..., HT1...

插入系统日志(描述)值('A')

打开 cData
开始交易流程数据
  -- 目前在这里尝试新的日志记录:
  -- 插入系统日志(描述)值('B')
  FETCH NEXT FROM cData INTO ...
  插入到系统日志(描述)值('C')
  ... ETC。

我收到的最后一条日志消息是“A”,然后一小时后它失败并显示上述消息,从未达到“C”。我现在正在尝试在“B”点记录。


根据要求,我发布了确切的 sql 表达式:

DECLARE cSource CURSOR LOCAL FORWARD_ONLY READ_ONLY
为了
    选择 MD.s 字段名称,
        MD.sFieldValue,
        TR.sTargetDataType,
        MD2.sFieldValue AS sUniqueID,
        TR.sTargetTableName,
        TR.sTargetFieldName,
        I.iRefCustomerID,
        I.iInterfaceID,
        IL.iRefInterfaceSessionID
    来自 MasterData MD
    加入 MasterData MD2
        ON MD.iRowIndex = MD2.iRowIndex
        AND MD.iBatchNumber = MD2.iBatchNumber
        AND MD.sTableName = MD2.sTableName
        AND MD2.sFieldName = 'sUniqueID'
    加入 SourceTargetRelation TR
        ON MD.sFieldName = TR.sSourceFieldName
        AND MD.sTableName = TR.sSourceTableName
    JOIN 接口Log IL
        ON IL.iInterfaceLogID = MD.iBatchNumber
    JOIN接口一
        ON I.iInterfaceID = IL.iRefInterfaceID
        AND TR.iRefSystemID = I.iRefSystemID
    在哪里
        MD.iBatchNumber = @iBatchNumber
    按 MD.sTableName、MD.iRowIndex 排序

在 Quassnoi 更新答案后,我还将原始索引发布在桌子上:

我在此表上有一个非聚集索引,其中包含iBatchNumbersFieldNamesTableName、列iRowIndex。该索引sFieldValue作为包含列。


正如 Quassnoi 建议的那样(我想我现在明白为什么了)我已经更改了索引以使列按以下顺序排列:iBatchNumber, sTableName, iRowIndex, sFieldName。我sFieldValue用作包含的列。执行计划不再包含任何内容SORT,并且执行计划中的步骤数不到原来的一半,我希望这也更快......

4

2 回答 2

7

你们有谁知道这其中的原因吗?或者如何使下面的查询更有效率?

您的查询使用ORDER BY.

这需要排序,排序需要临时空间。你已经离开了这个空间。

为避免这种情况,请在您的大表上创建一个复合索引:(col_filter_1, col_filter_2, col_order_1, col_order_2)col_filter_n您过滤的列在哪里,并且col_order_n是您排序的列。

这样的索引可用于过滤和排序过滤结果。

如果您发布您的实际查询(即您过滤和排序的表达式),我可能会更准确地告诉您如何创建这样的索引。

更新:

从您的查询中,我可以看到您需要一个索引(iBatchNumber, sTableName, iRowIndex, sFieldName)(按该顺序)。

如果您MD2在加入中领先也可能会有所帮助:

WHERE
    MD2.iBatchNumber = @iBatchNumber
ORDER BY
    MD2.sTableName, MD2.iRowIndex

查看执行计划并确保没有SORT使用任何操作。

于 2009-04-02T11:35:42.087 回答
0

你为什么使用游标?特别是在一张大桌子上?你在做什么不能基于集合完成?Curspr 对性能非常不利,如果存在其他替代方案,则不应使用。如果您根据您的选择找到的记录插入到另一个表中,那么没有游标可以做得更好。

于 2009-04-02T14:05:54.973 回答