Можно ли каждый раз выбирать разные строки, не зная полей для сортировки?

У меня есть запрос, скажем, X_QUERY, этот запрос может быть любым (мы не знаем ни одного поля) и может иметь сто миллионов строк. Мне нужно разделить результат на 16 фрагментов, чтобы каждый фрагмент имел совершенно разные строки X_QUERY. Мы могли бы предположить, что во время процесса нет обновлений ни в одной таблице.

Я решил ту же проблему в оракуле, используя ROWID как предложение order by, поэтому я попытался использовать CTID в Postgres, но не сработал.

SELECT * 
FROM (X_QUERY) as origin ORDER BY ctid -- <-- ctid does not exist here
limit 6250000 offset 0; -- <-- next offsets should be 6250000, 12500000 etc.

В идеале хотелось бы избежать дополнительных затрат на order by, но другого пути (по крайней мере, с помощью Oracle) я не нашел.

Итак, есть ли способ избежать какого-то порядка?
Если нет, есть ли способ каждый раз выбирать разные строки, не зная ни одного поля для заказа?

Пагинация в postgresql: citusdata.com/blog/2016/03/30/five-ways-to-paginate

ComplexityAverse 23.12.2020 16:19

Спасибо, но я так понимаю, что эти подходы не решают основной проблемы.

Emeeus 23.12.2020 17:36
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
1
2
219
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете добавить оконную функцию в X_QUERY с именем row_number().

Единственный возможный способ, который я вижу, - это использовать row_number() over(), и это не гарантирует один и тот же фрагмент каждый раз, когда мы запускаем один и тот же запрос, поэтому фрагменты не могут быть гарантированно отличными друг от друга.

Emeeus 23.12.2020 17:13

Хм. В вашем первом посте этой информации не было. Итак, строки X_QUERY не уникальны?

FrankBlack78 23.12.2020 18:12
Ответ принят как подходящий

Это один из редких случаев, когда я бы обратился к курсору SQL. Мануал по DECLARE:

DECLARE позволяет пользователю создавать курсоры, которые можно использовать для одновременного извлечения небольшого количества строк из более крупного запроса.

Он не заботится о базовом порядке сортировки и возвращает строки в той последовательности, в которой его создал запрос.

Используйте FETCH, чтобы получить следующий набор строк.

Пример:

BEGIN;
DECLARE x_cursor CURSOR FOR <X_QUERY>;  -- your query string here

FETCH 6250000 FROM x_cursor;
FETCH 6250000 FROM x_cursor;
FETCH 6250000 FROM x_cursor;
-- repeat until no more rows;

-- CLOSE x_cursor;  -- optional
COMMIT;
-- or ROLLBACK;  -- does not make a difference in this case

Все должно быть сделано в рамках транзакции, если вы не объявили корсор WITH HOLD. Инструкция:

Если не указано WITH HOLD, курсор, созданный этой командой можно использовать только в рамках текущей транзакции. Таким образом, DECLARE без WITH HOLD бесполезен вне блока транзакции: курсор будет существовать только до завершения оператора. Поэтому PostgreSQL сообщает об ошибке, если такая команда используется за пределами блок транзакций. Используйте BEGIN и COMMIT (или ROLLBACK), чтобы определить блок транзакций.

Если у вас есть запрос в виде строки, вы можете использовать динамический SQL в функции PL/pgSQL или оператор DO для динамического создания курсора SQL (WITH HOLD?) или использовать курсор PL/pgSQL для начала (связанный, но отдельная реализация).


Я пытался использовать CTID в postgres, но не работал.

Это потому, что ctid — это системный столбец, определяющий физическое расположение кортежа. Он не включается в результат запроса, если он явно не указан в списке SELECT. Таким образом, обычно это не результат данного запроса, и он не обязательно уникален в этой производной таблице. Следовательно, ctid можно использовать для обхода таблицы без одновременной записи, но это не подходит для ваших целей.
Более кровавые подробности:

Спасибо, отличное объяснение.

Emeeus 02.01.2021 17:18

Другие вопросы по теме