我正在尝试通过带有PostgreSQL 9.6的“同时创建索引”语句通过hikari创建索引 create语句被正在另一个表上工作的另一个事务阻止,并且事务状态为IIT(事务中的空闲)
wait_event_type | pid | state | query
Lock | 25707 | active | CREATE UNIQUE INDEX CONCURRENTLY IF NOT EXISTS "idx_tr-parameters__id_json" ON "tr-parameters" ((info->'_id') ASC)
| 25701 | idle in transaction | SELECT t.info FROM "configuration-profiles" t
05-29 21:22:53.458 [vert.x-worker-thread-11] DEBUG com.calix.sxa.VertxPGVertice - SELECT t.info FROM "organizations" t HikariProxyConnection@379242839 wrapping org.postgresql.jdbc.PgConnection@645bae4d
05-29 21:22:53.529 [vert.x-worker-thread-11] DEBUG com.zaxxer.hikari.pool.PoolBase - hikari-cp-threads - Reset (autoCommit) on connection org.postgresql.jdbc.PgConnection@645bae4d
05-29 21:22:53.533 [vert.x-worker-thread-11] DEBUG com.calix.sxa.VertxPGVertice - SELECT t.info FROM "configuration-profiles" t HikariProxyConnection@358392671 wrapping org.postgresql.jdbc.PgConnection@645bae4d
05-29 21:22:53.693 [vert.x-worker-thread-11] DEBUG com.calix.sxa.VertxPGVertice - SELECT t.info FROM "groups" t HikariProxyConnection@269112314 wrapping org.postgresql.jdbc.PgConnection@63822471
05-29 21:22:53.701 [vert.x-worker-thread-11] DEBUG com.zaxxer.hikari.pool.PoolBase - hikari-cp-threads - Reset (autoCommit) on connection org.postgresql.jdbc.PgConnection@63822471
05-29 21:22:53.701 [vert.x-worker-thread-11] DEBUG com.calix.sxa.VertxPGVertice - SELECT t.info FROM "configuration-profiles" t WHERE COALESCE((t.info->'configurations'->'parameterValues')::jsonb ?? 'OUI_FilterList', false) = true HikariProxyConnection@1431456353 wrapping org.postgresql.jdbc.PgConnection@63822471
05-29 21:22:53.704 [vert.x-worker-thread-11] DEBUG com.zaxxer.hikari.pool.PoolBase - hikari-cp-threads - Reset (autoCommit) on connection org.postgresql.jdbc.PgConnection@63822471
05-29 21:22:53.712 [vert.x-worker-thread-11] DEBUG com.calix.sxa.VertxPGVertice - CREATE INDEX CONCURRENTLY IF NOT EXISTS "idx_tr-parameters__id_json" ON "tr-parameters" ((info->>'timestamp') ASC) HikariProxyConnection@454316525 wrapping org.postgresql.jdbc.PgConnection@63822471
感谢您的帮助
如@jjanes所述,在并发建立索引的两次扫描期间,它被其他事务(同一表上的事务或具有快照的任何事务)阻止
官方文档还提到了[1]:https://www.postgresql.org/docs/9.1/sql-createindex.html#SQL-CREATEINDEX-CONCURRENTLY
After the second scan, the index build must wait for any transactions
that have a snapshot (see Chapter 13) predating the second scan to terminate
就我而言
wait_event_type | pid | state | backend_xid | backend_xmin | query
----------------+-------+---------------------+-------------+--------------+--------------------------------------------------
| 5226 | idle in transaction | | 7973432 | select * from "configuration-profiles"
backend_xmin是IIT的7973432,然后IIT使用快照阻止“并发创建索引”
顺便说一句,当使用隔离级别为“已读读”的命令行时,“并发创建索引”不会被阻止,但是对于Java代码,“ create”操作也会被相同的隔离级别阻止,
wait_event_type | pid | state | backend_xid | backend_xmin | query
----------------+-------+---------------------+-------------+--------------+--------------------------------------------------
| 5226 | idle in transaction | | 7973432 | select * from "configuration-profiles"
| 5210 | idle in transaction | | | select * from "configuration-profiles";
| 5455 | idle in transaction | | 7973432 | declare cur cursor for select * from "configuration-profiles";
如上所示,
答案 0 :(得分:1)
PostgreSQL无法知道其他连接将不希望使用在快照的将来某个时刻建立索引的表。仅仅因为它尚未使用过表,并不意味着它永远不会使用。肯定知道的方法是等待该事务(或快照)完成,这就是它的作用。
这两个SQL在异步模式下以不同的数据库连接在同一线程中运行
为什么另一个连接是IIT?还等什么呢? (它在代码中等待,不在数据库中)。由于它是异步的,因此它不应该等待CIC。它只是在等待您发出COMMIT吗?由于您关闭了自动提交,因此您有责任在适当的时候发出COMMIT。如果您使用的是更高的隔离级别,则即使仅SELECT语句也需要提交。
我试图通过命令行重现该问题,所有事情都运行良好,只需打开2个窗口,执行“开始;从A中选择*;”在第一个窗口中,并尝试执行“在B上同时创建索引”;在第二个窗口中,
您可以通过将第一个更改为begin isolation level repeatable read; select * from A;
解决方法: