#postgresql #materialized-views
Вопрос:
У меня есть проект, использующий базу данных postgres в бэкэнде, и я работаю над созданием файла Dockerfile, который может автоматически настроить локальный экземпляр базы данных для разработки. База данных включает в себя большое количество функций, и они исторически хранились в соответствующих контексту файлах sql, например users.sql, companies.sql. Это было нормально, так как всякий раз, когда вносятся изменения, я могу просто выполнить соответствующие файлы sql, которые REPLACE
все просматривают, и удалить/воссоздать все функции.
Однако при попытке запустить эти сценарии на новом экземпляре postgres (после CREATE
заполнения всех таблиц) они завершаются неудачей, поскольку большинство представлений/функций ссылаются на другие функции представлений, которые еще не определены.
Я начал исследовать, есть ли определенный порядок, в котором я могу запускать сценарии, чтобы избежать этой проблемы, но, поскольку они не были разработаны с учетом этой цели, это может оказаться невозможным, и в игре задействовано большое количество сущностей, так что это, скорее всего, нетривиальная задача.
Есть ли какой-либо способ добиться этого, кроме реструктуризации сценариев?
Комментарии:
1. Я считаю, что реструктуризация ваших сценариев и порядок, в котором вы их применяете, — это правильный (и единственный) путь. Возможно, вы можете проявить творческий подход, просматривая сценарии в поисках зависимостей для изменения порядка, но, вероятно, было бы быстрее просто выполнить вручную, так как это одноразовая вещь. Возможно, в качестве временного промежутка вы можете просто повторять сценарии снова и снова, пока не будут созданы все объекты, игнорируя ошибки, пока все ошибки не исчезнут… 🙁
2. Я подумал, что это, скорее всего, так, спасибо за вашу помощь!
3. База данных pg_dump -Cs > db.sql «рабочей» базы данных должна дать вам довольно хорошее представление о том, как реструктурировать инструкции create.
4. Это действительно обеспечивает более простое решение, но не позволяет нам хранить модульные sql-файлы так, как мы это делали для справки. Спасибо за идею.
Ответ №1:
Вы можете написать простой рекурсивный запрос, который начинается со всех представлений, которые не зависят от других, и рекурсивно добавляет представления, которые зависят от них. Затем выведите определение представления для этих представлений в правильном порядке, и вы получите свой сценарий:
WITH RECURSIVE viewids AS (
/* all views that don't depend on other views */
SELECT t.oid, 1 as level
FROM pg_class t
JOIN pg_rewrite AS r ON r.ev_class = t.oid
WHERE r.rulename = '_RETURN'
AND t.relkind = 'v'
AND t.relnamespace NOT IN ('pg_catalog'::regnamespace,
'information_schema'::regnamespace,
'pg_toast'::regnamespace)
AND NOT EXISTS (
/* depends on a view */
SELECT 1
FROM pg_depend AS d
JOIN pg_class AS t2 ON d.refobjid = t2.oid
WHERE d.objid = r.oid
AND d.classid = 'pg_rewrite'::regclass
AND d.refclassid = 'pg_class'::regclass
AND d.deptype = 'n'
AND d.refobjsubid <> 0
AND t2.relkind = 'v'
)
AND NOT EXISTS (
/* depends on an extension */
SELECT 1
FROM pg_depend
WHERE objid = t.oid
AND classid = 'pg_class'::regclass
AND refclassid = 'pg_extension'::regclass
AND deptype = 'e'
)
UNION ALL
/* all views that depend on these views */
SELECT t.oid, viewids.level 1
FROM pg_class AS t
JOIN pg_rewrite AS r ON r.ev_class = t.oid
JOIN pg_depend AS d ON d.objid = r.oid
JOIN viewids ON viewids.oid = d.refobjid
WHERE t.relkind = 'v'
AND r.rulename = '_RETURN'
AND d.classid = 'pg_rewrite'::regclass
AND d.refclassid = 'pg_class'::regclass
AND d.deptype = 'n'
AND d.refobjsubid <> 0
)
/* order the views by level, eliminating duplicates */
SELECT format('CREATE VIEW %s AS%s',
oid::regclass,
pg_get_viewdef(oid::regclass))
FROM viewids
GROUP BY oid
ORDER BY max(level);
Комментарии:
1. Как можно включить материализованные представления в этот запрос? И почему материализованные представления обрабатываются по-разному? Например, phpPgAdmin перечисляет не материализованные представления, а представления. Спасибо
2. pgpPgAdmin может не знать о материализованных представлениях. Чтобы включить их, вы должны включить
pg_class
записи сrelkind = 'm'
.