繁体   English   中英

在PostgreSQL 9.6中创建被其他事务同时阻止的索引

[英]Create index concurrently blocked by other transactions in postgresql 9.6

我正在尝试通过带有PostgreSQL 9.6的“同时创建索引”语句通过hikari创建索引,该create语句被正在另一个表上工作的另一个事务阻止,并且事务状态为IIT(事务中的空闲)

  1. 该代码通过hikari连接池动态创建索引
  2. 所有操作只有一个连接池,例如选择/创建索引等
  3. 2个SQL在异步模式下以不同的数据库连接在同一线程中运行
  4. 当使用“创建索引”而不是“同时创建索引”时,一切正常
  5. PostgreSQL显示“在B上同时创建索引”(活动)被“从A中选择*”阻止(事务中的空闲)
  6. 我试图通过命令行重现该问题,所有事情都运行良好,仅打开2个窗口,执行“开始;从A中选择*;” 在第一个窗口中,并尝试执行“在B上同时创建索引”; 在第二个窗口中,按预期方式创建了索引,没有发生任何块(我检查了第一个处于“ IIT”状态)
  7. 要在游标上使用fetch_size,当从池中获取连接时,select语句将禁用自动提交,并通过hikari自身将值与池全局设置一起重新设置,默认池设置为autocommit = true
  8. 2条语句在不同的表上工作,这2个表之间没有关系
  9. 当“ 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

  1. 我不知道为什么会发生块,因为表完全不同,并且当使用2个命令行窗口手动测试时,所有事情都运行良好
  2. 如何解决此问题? 任何解决方法吗?

谢谢您的帮助


如@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代码,“创建”操作也会被相同的隔离级别阻止,

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";

如上所示,

  1. 使用“从“配置文件”中选择*;” 在命令行中,因为没有打开游标,所以没有backend_xmin,执行该语句后应返回所有记录
  2. 使用“声明cur光标从“ configuration-profiles”中选择*;” 在命令行中,自从游标打开并等待查询以来,backend_xmin具有值
  3. 通过Java使用“来自“配置文件”的select *”,backend_xmin也具有价值,因为lib也使用游标

PostgreSQL无法知道其他连接将不希望使用在快照的将来某个时刻建立索引的表。 仅仅因为它尚未使用过表,并不意味着它永远不会使用。 确切知道的方法是等待该事务(或快照)完成,这就是它的作用。

2个SQL在异步模式下以不同的数据库连接在同一线程中运行

为什么另一个连接是IIT? 还等什么呢? (它在代码中等待,不在数据库中)。 由于它是异步的,因此它不应该等待CIC。 它只是在等待您发出COMMIT吗? 由于您关闭了自动提交,因此您有责任在适当的时候发出COMMIT。 如果您使用更高的隔离级别,那么即使仅SELECT语句也需要提交。

我试图通过命令行重现该问题,所有事情都运行良好,仅打开2个窗口,执行“开始;从A中选择*;” 在第一个窗口中,并尝试执行“在B上同时创建索引”; 在第二个窗口中

您可以通过更改第一个来begin isolation level repeatable read; select * from A;begin isolation level repeatable read; select * from A; begin isolation level repeatable read; select * from A;

解决方法:

  1. 不要在公开交易中闲逛
  2. 不要使用比您需要的更高的隔离级别。
  3. 不要使用CIC。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM