【发布时间】:2013-10-17 20:53:23
【问题描述】:
我有桌子说
TAB1
ID, TARGET, STATE, NEXT
ID 列是主键。
显示死锁的查询与此类似
SELECT *
FROM TAB1
WHERE NEXT = (SELECT MIN(NEXT) FROM TAB1 WHERE TARGET=? AND STATE=?) FOR UPDATE
我做了一个解释计划,我看到这样的东西:
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 8095 | 6 (0)| 00:00:01 |
| 1 | FOR UPDATE | | | | | |
| 2 | BUFFER SORT | | | | | |
|* 3 | TABLE ACCESS FULL | TAB1 | 1 | 8095 | 3 (0)| 00:00:01 |
| 4 | SORT AGGREGATE | | 1 | 2083 | | |
|* 5 | TABLE ACCESS FULL| TAB1 | 1 | 2083 | 3 (0)| 00:00:01 |
由于查询执行 TABLE ACCESS FULL 两次,所以我怀疑执行相同查询的 2 个会话将以不同的顺序访问行。
列索引是否有助于防止死锁?说在 NEXT 上创建索引???或者通过将主键更改为非集群键?注意:正常情况下,表格最多有 1000 行。
【问题讨论】:
-
SQL 只是 结构化查询语言 - 许多数据库系统使用的语言,但不是数据库产品...许多事情是特定于供应商的 - 所以我们真的需要知道您正在使用什么数据库系统(以及哪个版本)(请相应地更新标签)......
-
这里可能会出现死锁,索引也无济于事,请给我们更多信息——你想做什么?
-
我假设您没有索引。建议在 TARGET/STATE 和可能的 NEXT(即 one 索引)上设置一个,在 NEXT 上设置一个单独的索引。但是,有更有效的方法可以做到这一点,而无需再次扫描表。 For instance。 Nothing 将在您锁定表时停止锁定。唯一的解决方案是不锁定表或让您的其他查询使用
nowait,以便它们忽略锁定的行。 -
无需猜测哪些查询导致了死锁。每个死锁都会生成一个跟踪文件,该跟踪文件会告诉您究竟是哪些语句导致了问题。如果您知道其中一个死锁发生的确切时间,请让 DBA 查找当时生成的跟踪文件。
-
请显示整个事务 --> 事务执行的所有命令,直到提交。 Trace 显示
SELECT * ... FOR UPDATE,但这不一定是导致死锁的主要原因。
标签: oracle oracle11g database-deadlocks