Почему этот запрос тупиковый? - PullRequest
2 голосов
/ 24 октября 2011

У меня есть приложение, которое читает структуру существующей базы данных 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 Ответ

1 голос
/ 25 октября 2011

Я проверил и наш запрос очень медленно тоже.Корень этой проблемы в том, что «таблицы» в information_schema на самом деле представляют собой сложные представления для предоставления каталогов в соответствии со стандартом SQL.В этом конкретном случае все еще сложнее, поскольку внешние ключи могут быть построены на нескольких столбцах.Ваш запрос дает повторяющихся строк для тех случаев, которые, я подозреваю, могут быть нежелательным побочным эффектом.

Это также причина для конструкции подзапроса с unnest и ARRAYв моем запросе ниже.

Пожалуйста, рассмотрите этот альтернативный запрос.Он выдает ту же информацию, просто без повторяющихся строк и в 100 раз быстрее .Кроме того, я рискну гарантировать, без взаимных блокировок.

Конечно, этот запрос работает только для PostgreSQL и не переносим на другие СУБД.

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

Я использую специальную операция литья table_oid::regclass.который выдает имена таблиц, как видно из вашего текущего активного search_path.Это может или не может быть то, что вы хотите.Чтобы этот запрос включал абсолютный путь (схему) для каждого имени таблицы, вы можете установить search_path следующим образом :

SET search_path = pg_catalog;
SELECT ...

Вы, вероятно, знаете остальное, ноЯ включил его для широкой публики.
Если вы продолжите эту сессию и захотите вернуться по умолчанию для search_path, тогда:

RESET search_path;

В случае, если вы должны использовать пользовательский search_path, выпришлось бы установить его снова.

...