【发布时间】:2012-03-07 11:02:03
【问题描述】:
解析一些数据并将其插入 .NET 的 3 个表中。使用表值参数传递数据,因为某些插入是 600,000 行。传递对象(不是 DataTables),它们是通过引用传递的(TVP 的性质)。由于插入值一次限制为 1000 行,因此与直接值插入相比获得了 100:1 的增益。在存储过程中,从 TVP 到实际表的插入按聚集索引排序。这些表除了聚集索引之外没有其他索引。 SP 采用 TABLOCK,因为它们是一次写入表和一个数据加载器。填充因子 100。数据或事务日志大小没有增加 - 它的大小适合总数据负载。终于到问题了。在过去 4 小时内插入了 2 亿行。插入响应时间减少了 1/2。如果填充因子为 100 并且我插入的是按聚集索引排序的,那么为什么响应下降?我能做些什么来解决这个问题?
直到我使用它才获得 TVP - 它就像一个反向 DataReader。
感谢您的帮助,并为不正确的问题陈述道歉。对于每个解析(在本例中我解析 200,000),插入按聚集索引排序。然而,对于 3 个表中只有 1 个表是下一个整体以聚集索引顺序进行的解析。解析 70,000 后,好表的扫描密度为 99%,但其他两个表碎片严重,扫描密度为 12%。
将两个碎片表的填充因子设置为 50 并重新建立索引。现在我得到了大约 1/3 的最大速度。我只需要每隔几个小时停止该过程并重新编制索引。
我最终做的是更改聚集索引以匹配插入顺序。对曾经聚集的内容创建了唯一索引。我禁用唯一,索引插入数据,然后重建唯一索引。在这种情况下,我在 10 小时的跑步中获得了 300:1 的性能。这不是一个额外的 0 - 三百比一。这并不是捏造的 - 与从排序索引和填充因子或 30 开始相比。即使有额外的索引,我的表大小也更小,因为我可以将两个填充因子都设置为 100。
我在某些查询中使用#temp,因此我可以按照只有查询知道的顺序获取行。我将#temp 转换为TVP 并获得了1/2 秒(大约是创建和删除#temp 所需的时间)。
【问题讨论】:
-
我假设目标表上没有约束、触发器或非聚集索引?抱歉,我没有对 TVP 进行太多性能分析,所以我不确定还有什么可能会干扰。哦,我编辑了标签,它确实已经存在。 :-)
-
@AaronBertrand 谢谢,我没有找到标签。整个数据库中没有触发器。有两个约束,但约束侧表没有更改。如果我的代码没有被破坏,那么应该没有违反约束。你认为我应该禁用插入的约束检查吗?如果我禁用约束检查并且违反了约束会发生什么。在这种情况下,TVP 类似于批量复制,但来自内存对象。直接从用于在解析中查找唯一值和唯一值对的一些字典中提供 TVP。
-
错误的是三个表之一上有一个非聚集索引。该表是三个表中最小的一个,乘以 100 倍,并且非聚集索引位于单个列上。表上的索引为 160 KB,大约是其他两个索引总和的两倍。仅此一项就可以解释速度下降吗?我想我可以填写索引并进行测试?
-
你有自动更新统计数据吗?
-
除了@SqlACID 提到的自动统计之外,随着表填满,约束检查可能会变得更加昂贵。如果我要认真加载一个表,我通常计划禁用或删除索引和约束,然后重新创建它们,如果速度是我的最终目标。这可能意味着如果违反了约束,则事后删除行,或者在可能的情况下对批量数据进行更好的验证。
标签: sql-server-2008 table-valued-parameters