使用 Oracle PL/SQL 表时更新缓慢
我们使用 PL/SQL 表(名为 pTable)来收集许多要更新的 id。
然而,该语句
UPDATE aTable
SET aColumn = 1
WHERE id IN (SELECT COLUMN_VALUE
FROM TABLE (pTable));
需要很长时间才能执行。
看起来优化器提出了一个非常糟糕的执行计划,它没有使用 id 上定义的索引(作为主键),而是决定对 aTable 使用全表扫描。 pTable 通常包含很少的值(大多数情况下只有一个)。
我们可以做些什么来加快速度?我们想出的最好办法是将低 pTable.Count(1 和 2)作为特殊情况处理,但这肯定不是很优雅。
感谢所有的好建议。我在我的博客 http:// /smartercoding.blogspot.com/2010/01/performance-issues-using-plsql-tables.html。
We're using a PL/SQL table (named pTable) to collect a number of ids to be updated.
However, the statement
UPDATE aTable
SET aColumn = 1
WHERE id IN (SELECT COLUMN_VALUE
FROM TABLE (pTable));
takes a long time to execute.
It seems that the optimizer comes up with a very bad execution plan, instead of using the index that is defined on id (as the primary key) it decides to use a full table scan on the aTable. pTable usually contains very few values (in most cases just one).
What can we do to make this faster? The best we've come up with is to handle low pTable.Count (1 and 2) as special cases, but that is certainly not very elegant.
Thanks for all the great suggestions. I wrote about this issue in my blog at http://smartercoding.blogspot.com/2010/01/performance-issues-using-plsql-tables.html.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
这是另一种方法。创建临时表:
要执行更新,请使用
pTable
的内容填充pTempTable
并执行:无需借助优化器提示即可执行相当好的操作。
Here's another approach. Create a temporary table:
To perform the update, populate
pTempTable
with the contents ofpTable
and execute:The should perform reasonably well without resorting to optimizer hints.
糟糕的执行计划可能是不可避免的(不幸的是)。 PL/SQL 表没有统计信息,因此优化器无法知道其中的行数。是否可以在更新中使用提示?如果是这样,您可能会强制以这种方式使用索引。
The bad execution plan is probably unavoidable (unfortunately). There is no statistics information for the PL/SQL table, so the optimizer has no way of knowing that there are few rows in it. Is it possible to use hints in an UPDATE? If so, you might force use of the index that way.
它有助于告诉优化器使用“正确的”索引,而不是进行疯狂的全表扫描:
我无法将此解决方案应用于更复杂的场景,但找到了其他解决方法。
It helped to tell the optimizer to use the "correct" index instead of going on a wild full-table scan:
I couldn't apply this solution to more complicated scenarios, but found other workarounds for those.
您可以尝试添加 ROWNUM < ...条款。
在此测试中,ROWNUM < 30 更改了使用索引的计划。
当然,这取决于您的值集是否具有合理的最大大小。
You could try adding a ROWNUM < ... clause.
In this test a ROWNUM < 30 changes the plan to use an index.
Of course that depends on your set of values having a reasonable maximum size.
我想知道 PL/SQL 表的子查询中的 MATERIALIZE 提示是否会强制临时表实例化并帮助优化器?
I wonder if the MATERIALIZE hint in the subselect from the PL/SQL table would force a temp table instantiation and help the optimizer?
您可以尝试基数提示。如果您(大致)知道集合中的行数,这会很好。
You can try the cardinality hint. This is good if you know (roughly) the number of rows in the collection.