为什么这个查询死锁?

时间:2011-10-24 16:40:35

标签: postgresql catalog information-schema

我有一个应用程序,它读取现有PostgreSQL 9.1数据库的结构,将其与“应该”状态进行比较,并相应地更新数据库。大部分时间都可以正常工作。但是,在读取当前数据库结构死锁时,我现在有几个实例。负责的查询读取现有的外键:

SELECT tc.table_schema, tc.table_name, tc.constraint_name, kcu.column_name,
       ccu.table_schema, ccu.table_name, ccu.column_name
FROM information_schema.table_constraints AS tc
JOIN information_schema.key_column_usage AS kcu
     ON tc.constraint_name = kcu.constraint_name
JOIN information_schema.constraint_column_usage AS ccu
     ON ccu.constraint_name = tc.constraint_name
WHERE constraint_type = 'FOREIGN KEY'

在pgAdmin中查看服务器状态表明这是服务器上运行的唯一活动查询/事务。但是,查询仍未返回。

错误在某种程度上是可重现的:当我找到产生错误的数据库时,每次都会产生错误。但并非所有数据库都会产生错误。这是一个神秘的错误,我已经没有选择和想法,还有什么可以尝试或如何解决这个问题。所以任何意见或想法都受到高度赞赏!

PS:我的一位同事刚报道他使用PostgreSQL 8.4产生了同样的错误。

1 个答案:

答案 0 :(得分:1)

我测试过并发现您的查询非常慢。这个问题的根源是information_schema中的“表”实际上是根据SQL标准提供目录的复杂视图。在这种特殊情况下,由于可以在多个列上构建外键,因此事情变得更加复杂。对于那些我怀疑可能会产生不良副作用的案例,您的查询会产生重复行

这也是下面我的查询中带有unnestARRAY的子查询构造的原因。

请考虑此替代查询。它产生的信息相同,只是没有重复的行,而且快了100倍。此外,我冒昧地保证,没有死锁。

当然,此查询仅适用于PostgreSQL,不能移植到其他RDBMS。

SELECT c.conrelid::regclass AS table_name
      ,c.conname AS fk_name
      ,ARRAY(SELECT a.attname
             FROM   unnest(c.conkey) x
             JOIN   pg_attribute a
             ON     a.attrelid = c.conrelid AND a.attnum = x) AS fk_columns
      ,c.confrelid::regclass AS ref_table
      ,ARRAY(SELECT a.attname
             FROM   unnest(c.confkey) x
             JOIN   pg_attribute a
             ON     a.attrelid = c.confrelid AND a.attnum = x) AS ref_columns
FROM   pg_catalog.pg_constraint c
WHERE  c.contype = 'f';
-- ORDER  BY c.conrelid::regclass::text,2

我使用special casting operation table_oid::regclass。这会产生与当前活动的search_path一起看到的表名。这可能是也可能不是你想要的。要使此查询包含每个表名的绝对路径(模式),您可以set the search_path like this

SET search_path = pg_catalog;
SELECT ...

你可能知道其余的,但我把它包括在普通大众中。
如果您继续参加此会话并希望恢复默认的search_path,那么:

RESET search_path;

如果您应该使用自定义search_path,则必须重新设置。