Как эффективно сохранить новейшие строки только в операторе WITH RECURSIVE? - PullRequest
0 голосов
/ 28 апреля 2018

У меня есть несколько начальных строк в таблице. Я хотел бы изменить их с помощью рекурсивного вызова. В моем примере кода эта функция является простым умножением на два, и я хотел бы выполнить ее 5 раз:

WITH RECURSIVE cte (n,v) AS
(

  -- initial values
  SELECT 0,2
  UNION ALL
  SELECT 0,3

  UNION ALL

  -- generator
  SELECT n + 1, v * 2 FROM cte WHERE n < 5
)
SELECT v FROM cte where n = 5;

Это работает, но моя проблема в том, что он только отфильтровывает ненужные значения в конце запроса. Если я начну с гораздо большего количества строк, это может ухудшить производительность, потому что у меня в памяти будет больше строк, чем нужно. Можно ли сохранить новейшие значения только в каждой итерации?

SQLFiddle: http://sqlfiddle.com/#!5/9eecb7/6761

Ответы [ 2 ]

0 голосов
/ 29 апреля 2018

В SQLite CTE реализован как сопрограмма (как показано в выводе EXPLAIN ), поэтому в памяти сохраняется только текущая строка, и производительность не снижается из-за использования памяти.

MySQL не разрешает LIMIT в рекурсивной части SELECT . Если я правильно интерпретирую WL # 3634 , реализация в версии 8.0 всегда полностью материализует рекурсивные CTE.

Так что в SQLite вам не нужно ничего делать, а в MySQL вы ничего не можете делать.

0 голосов
/ 28 апреля 2018

В SQLite вы можете использовать предложение OFFSET

  • Предложение OFFSET, если оно присутствует и имеет положительное значение N, предотвращает добавление первых N строк в рекурсивную таблицу. первые N строк по-прежнему обрабатываются с помощью рекурсивного выбора - они просто не добавляются в рекурсивную таблицу. Ряды не учитываются выполнение LIMIT, пока все строки OFFSET не будут пропущены.

Демо: http://sqlfiddle.com/#!5/9eecb7/6804

WITH RECURSIVE cte (n,v) AS
(

  -- initial values
  SELECT 0,2
  UNION ALL
  SELECT 0,3

  UNION ALL

  -- generator
  SELECT n + 1, v * 2 FROM cte WHERE n < 5 LIMIT 1000 OFFSET 10

)
SELECT * FROM cte

| n |  v |
|---|----|
| 5 | 64 |
| 5 | 96 |

В приведенном выше примере смещение рассчитывается как число начальных строк в начальном выборе (2 строки), умноженное на число итераций (5) => 2 * 5 = 10


Кстати, в этом конкретном примере лучшим решением было бы вычисление простого X * 2^5
(X мл, умноженного на степень от 2 до 5) вместо рекурсии.

...