Из комментария к этому посту:
Ваш запрос использует genotype_pos_ind
и фильтрует по aliquot_barcode
.Попробуйте удалить (временно) genotype_pos_ind
, и если это не сработает, найдите способ принудительного использования индекса.
Ваш запрос должен использовать вместо этого genotype_pk
.
Из чегоВы сказали, что может быть много записей с одинаковыми значениями для aliquot_barcode
, chrom
, start
и end
, поэтому СУБД потребуется много времени для фильтрации каждого aliquot_barcode
.
И если это все еще слишком долго для вас, вы можете попробовать мой старый ответ, который я сохраню для дальнейших ссылок:
К сожалению, я выигралне могу оптимизировать ваш запрос: слишком много вещей, чтобы принять во внимание.Построить результат с 9 миллионами записей из 13 полей может быть слишком много: может произойти перестановка, ваша ОС не позволит выделять столько памяти, а также будет делать JOIN
и т. Д. (написано до реального ответа...)
Я использовал для оптимизации некоторый запрос, состоящий из пятнадцати таблиц из 10 миллионов записей.SELECT
такого размера никогда не будет выполнимо в разумные сроки (менее 10 часов).
У меня нет СУБД для проверки того, что я говорю.Кроме того, я не делал SQL в течение полугода: p Поиск того, почему это занимает так много времени (как вы и просили), будет слишком трудоемким, поэтому вот еще одно решение исходной проблемы.
Я принял решение создать временную таблицу:
- Создать временную таблицу:
tmp_analysis
с теми же полями, что и у SELECT
+ некоторые служебные поля:
Поле идентификатора (tmp_ID
, большое целое число), логическое значение, чтобы проверить, была ли запись обновлена (tmp_updated), и отметка времени, чтобы проверить, когда она была обновлена (tmp_update_time
).И, конечно, все поля с одинаковыми типами данных из исходных SELECT
(из vca
и gt
)
Вставьте все свои записи из
vca
:
Используйте null
(или любое другое значение по умолчанию, если вы не можете) для полей из gt
на данный момент.Установите tmp_updated
в false.Используйте простой count()
для первичного ключа.
Обновите все эти записи полями из gt.
Используйте WHERE
вместо JOIN
:
UPDATE tmp_analysis as tmp -- I don't think you need to use a schema to call tmp_analysis
SET tmp_update = true,
tmp_update_time = clock_timestamp(),
tmp.mutect2_call = gt.called
gt.ref_count,
gt.alt_count,
gt.read_depth,
gt.called = -- ... (your CASE/WHEN/ELSE/END should work here)
FROM
analysis.snv_genotypes gt
WHERE --JOIN should work too
tmp.aliquot_barcode = gt.aliquot_barcode AND
tmp.chrom = gt.chrom AND
vca.start = gt.start AND
tmp."end" = gt."end" AND
tmp.alt::text = gt.alt::text
Я сказал, что вы должны использовать EXISTS
из соображений производительности, но я ошибся, так как не думаю, что вы можете получить поля из условия EXISTS
.Возможно, есть способ сказать Postgresql, что это отношения один на один, но я не уверен.Во всяком случае, индекс
Очевидно,
SELECT
ваша
tmp_analysis
таблица для получения ваших записей!
Некоторые примечания для этого:
- Если это занимает слишком много времени:
Используйте поле tmp_ID
, чтобы ограничить количество обновлений, например, до 10 000, и проверьте план выполнения 3-го запроса (UPDATE
): необходимо выполнить полное сканирование натаблица временных таблиц и сканирование индекса на gt
(на genotype_pk
).Если нет, проверьте свои индексы и поищите, как принудительно использовать индексы PGSL.Вы должны использовать WHERE tmp_ID < 10000
вместо LIMIT 10000
.IIRC, LIMIT
выполнит весь запрос и просто выдаст вам часть результата.
Если это все еще занимает слишком много времени:
Сегментируйте запрос с помощью tmp_ID
и (как вы сказали) используйте оператор цикла в UPDATE
для запросас 100 000 или менее записей одновременно (снова используйте where tmp_ID < x AND tmp_ID > y
).Проверьте план выполнения еще раз: полное сканирование должно быть ограничено tmp_id
до сканирования индекса.Не забудьте добавить индекс для этого поля (если это еще не первичный ключ).
Если вам понадобится повторить это позже:
Используйте BEGIN/END TRANSACTION
для инкапсуляции всех запросов и опцию TEMPORARY TABLE
для CREATE TABLE tmp_analysis
, чтобы вам не приходилось чиститьtmp_analysis после выполнения запроса.
Если у вас все еще есть проблема с циклами:
Используйте транзакции внутри цикла и остановите его, если он снова зависнет.Затем вы можете восстановить его позже с меньшим размером петли.
Если вы хотите немного уменьшить время выполнения:
Вы можете выполнить шаги 1 и 2 в одном запросе с INSERT .. AS .. SELECT
, но я не помню, как установить тип данныхдля полей с gt
, поскольку они будут установлены в ноль.Обычно это должно быть немного быстрее в целом.
Если вам интересно:
И запрос без цикла по-прежнему занимает более 10 часов, остановите его и проверьте tmp_update_time, чтобы увидеть, как изменяется время выполнения, возможно, оно даст вамподсказка о том, почему оригинальный запрос не сработал.В PGSQL есть несколько параметров конфигурации для ограничения использования ОЗУ, использования диска, потоков.Ваша ОС может устанавливать собственные ограничения и проверять замену диска, использование кэша ЦП и т. Д. (Я думаю, что вы уже сделали это, но я не проверял)