MariaDB: Как использовать «INSERT ... SELECT» с оператором WITH - PullRequest
0 голосов
/ 07 июня 2019

Примечание: это включает ColumnStore.

На работе у нас есть большой оператор SQL, который требует слишком много памяти для выполнения на prod.В настоящее время я работаю над уменьшением размера, который потребляет запрос.Я пытался использовать разные подходы, но до сих пор ничего не решило проблему, за исключением WITH ... AS (...), по некоторым причинам.Однако мне нужно объединить это с INSERT INTO ....

Это код, который я пытаюсь заставить работать

TRUNCATE db1.myTable;

INSERT INTO db1.myTable(`all`, `needed`, `columns`)
(WITH everything AS (
  SELECT all, needed, columns
   FROM db1.mainTable T1
   JOIN db1.secondTable T2
     ON (T1.someCol = T2.someCol)
   JOIN db2.thirdTable T3
     ON (T1.anotherCol = T3.anotherCol)
   LEFT JOIN db1.fourthTable T4
     ON (T4.anotherCol = T1.anotherCol)
   WHERE T2.yetAnotherCol >= (some_SELECT_subquery)
     AND T1.valid = 1
) SELECT * FROM everything);

EXPLAIN (WITH everything AS ... возвращает

+------+-------------+-----------------------+------+---------------+------+---------+------+------+-------------------------------------------------+
| id   | select_type | table                 | type | possible_keys | key  | key_len | ref  | rows | Extra                                           |
+------+-------------+-----------------------+------+---------------+------+---------+------+------+-------------------------------------------------+
|    1 | PRIMARY     | <derived2>            | ALL  | NULL          | NULL | NULL    | NULL | 16000000000000 |                                                 |
|    2 | PRIMARY     | T1                    | ALL  | NULL          | NULL | NULL    | NULL | 2000 | Using where with pushed condition               |
|    2 | PRIMARY     | T2                    | ALL  | NULL          | NULL | NULL    | NULL | 2000 | Using where; Using join buffer (flat, BNL join) |
|    2 | PRIMARY     | T3                    | ALL  | NULL          | NULL | NULL    | NULL | 2000 | Using where; Using join buffer (flat, BNL join) |
|    2 | PRIMARY     | T4                    | ALL  | NULL          | NULL | NULL    | NULL | 2000 | Using where                                     |
|    3 | SUBQUERY    | some_SELECT_subquery  | ALL  | NULL          | NULL | NULL    | NULL | 2000 | Using where with pushed condition               |
+------+-------------+-----------------------+------+---------------+------+---------+------+------+-------------------------------------------------+
5 rows in set (0,21 sec)

Если я использую только WITH заявление, я могу заставить его работать.Например, я не использую INSERT INTO.Никаких проблем, и запрос еще быстрее.Я также провел быстрое тестирование, пытаясь разделить запрос на несколько WITH с, но сдался, так как считаю, что перепутал синтаксис.Я не слишком хорошо разбираюсь в SQL, и тем более в JOIN s (младший разработчик).

Когда я комбинирую WITH утверждение с INSER INTO ..., MariaDB отвечает ERROR 1064 (42000) at line 3: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ') SELECT * FROM everything)' at line 1,Я также попытался добавить точку с запятой после ... valid = 1, слить две последние строки, расположить открытые скобки после ... AS на новой строке, и некоторые другие проблемы, о которых я мог подумать, могут быть связаны с синтаксисом.Не повезло.

В настоящее время я думаю, что вы не можете объединить INSERT INTO ... SELECT ... с WITH ....По крайней мере, не иметь WITH в начале, где должен быть SELECT.Это то, что я могу получить из документов .

Итак, вкратце, мой вопрос: могу ли я вообще объединить INSERT INTO ... SELECT с WITH заявлением?Если нет, могу ли я добиться чего-то похожего с другой техникой?

Есть ли другие способы улучшить использование памяти моего запроса?Я бы предпочел не связываться с параметрами конфигурации для MariaDB или Docker, но если это единственная возможность, я рассмотрю это.

Ответы [ 2 ]

0 голосов
/ 11 июня 2019

Хотя я не нашел ответа на свой первоначальный вопрос, мы решили обойти эту проблему, сократив объем данных, собранных в подзапросе.Я не раскрыл это в первоначальном вопросе, потому что это не было решением, о котором я знал при публикации вопроса.Мы просто вызовем SQL из скрипта Python, где можем циклически перебирать номера недель, которые мы хотим получить.

WHERE T2.ID >= (SELECT ID - {week_number} FROM db1.secondTable WHERE NOW() BETWEEN monday AND sunday) AND T1.valid = 1);
0 голосов
/ 10 июня 2019

Вы пробовали это?

 TRUNCATE db1.myTable;


WITH everything AS (
  SELECT all, needed, columns
   FROM db1.mainTable T1
   JOIN db1.secondTable T2
     ON (T1.someCol = T2.someCol)
   JOIN db2.thirdTable T3
     ON (T1.anotherCol = T3.anotherCol)
   LEFT JOIN db1.fourthTable T4
     ON (T4.anotherCol = T1.anotherCol)
   WHERE T2.yetAnotherCol >= (some_SELECT_subquery)
     AND T1.valid = 1
) INSERT INTO db1.myTable SELECT * FROM everything;
...