我们正在尝试设置游标来运行从同一巨大表的两个“实例”之间的连接生成的记录(超过150条记录)。
出现以下异常消息:
无法为数据库'tempdb'中的对象'dbo.SORT临时运行存储:165282123350016'分配空间,因为'PRIMARY'文件组已满。通过删除不需要的文件,删除文件组中的对象,向文件组添加其他文件或为文件组中的现有文件设置自动增长来创建磁盘空间。
你们有谁知道这个的原因吗?或者如何使下面的查询更有效?
我发现它出现在DECLARE CURSOR
和第一个FETCH NEXT
之间的某个地方,但我还不知道它是否介于... {/ p>之间
DECLARE CURSOR
和OPEN
或之间
OPEN
和第一个FETCH NEXT
。更多细节:sql语句如下所示:
DECLARE cData CURSOR LOCAL FORWARD_ONLY READ_ONLY FOR SELECT ... FROM HugeTable HT1 JOIN HugeTable HT2 ON .. JOIN Table3 ON .. JOIN Table4 ON .. JOIN Table5 ON .. WHERE ... ORDER BY HT1..., HT1... INSERT INTO SysLog (Description) VALUES ('A') OPEN cData BEGIN TRANSACTION ProcessData -- Currently trying new logging here: -- INSERT INTO SysLog (Description) VALUES ('B') FETCH NEXT FROM cData INTO ... INSERT INTO SysLog (Description) VALUES ('C') ... etc.
我得到的最后一条日志消息是'A',然后一小时后它失败并显示上述消息,从未到达'C'。我现在正尝试在'B'点进行记录。
根据要求我发布了确切的sql表达式:
DECLARE cSource CURSOR LOCAL FORWARD_ONLY READ_ONLY FOR SELECT MD.sFieldName, MD.sFieldValue, TR.sTargetDataType, MD2.sFieldValue AS sUniqueID, TR.sTargetTableName, TR.sTargetFieldName, I.iRefCustomerID, I.iInterfaceID, IL.iRefInterfaceSessionID FROM MasterData MD JOIN MasterData MD2 ON MD.iRowIndex = MD2.iRowIndex AND MD.iBatchNumber = MD2.iBatchNumber AND MD.sTableName = MD2.sTableName AND MD2.sFieldName = 'sUniqueID' JOIN SourceTargetRelation TR ON MD.sFieldName = TR.sSourceFieldName AND MD.sTableName = TR.sSourceTableName JOIN InterfaceLog IL ON IL.iInterfaceLogID = MD.iBatchNumber JOIN Interface I ON I.iInterfaceID = IL.iRefInterfaceID AND TR.iRefSystemID = I.iRefSystemID WHERE MD.iBatchNumber = @iBatchNumber ORDER BY MD.sTableName, MD.iRowIndex
在Quassnoi的更新答案之后,我还在表格上发布了原始索引:
我在这个表上有一个非聚集索引,列iBatchNumber
,sFieldName
,sTableName
,iRowIndex
。该索引的sFieldValue
为包含列。
正如Quassnoi建议的那样(我想我现在理解为什么)我已经更改了索引以按此顺序排列:iBatchNumber
,sTableName
,iRowIndex
,{{1} }。我使用sFieldName
作为包含列。执行计划不再包含任何sFieldValue
,并且执行计划中的步骤数量不到原始步骤的一半,我希望它也更快......
答案 0 :(得分: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
操作。
答案 1 :(得分:0)
为什么使用光标?特别是在一张大桌子上?你在做什么不能做到基于集合? Cursprs对性能非常不利,如果存在其他替代方案,则不应使用。如果您根据您的选择找到的记录插入另一个表,没有光标可以做得更好。