Оптимизация SQL: удаление занимает много времени - PullRequest
2 голосов
/ 16 марта 2010

У меня есть SQL-запрос Oracle как часть хранимого процесса:

DELETE FROM item i 
 WHERE NOT EXISTS (SELECT 1 FROM item_queue q WHERE q.n=i.n) 
 AND NOT EXISTS (SELECT 1 FROM tool_queue t WHERE t.n=i.n);

Немного о таблицах:

  • элемент содержит около 10 тыс. Строк с индексом в столбце n
  • item_queue содержит около 1 миллиона строк, также с индексом по n столбцу
  • tool_queue также содержит около 5 миллионов проиндексированных строк

Мне интересно, можно ли каким-либо образом оптимизировать запрос / подзапросы, чтобы ускорить их выполнение, я подумал, что удаление обычно довольно быстрое

Ответы [ 7 ]

4 голосов
/ 16 марта 2010

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

В противном случае примечание - удаление не самая быстрая вещь вокруг. МНОГИЕ вещи случаются при удалении.

OTOH Я серьезно думаю .... проблема в двух подзапросах. Как выглядит план запроса?

3 голосов
/ 16 марта 2010

Попробуйте что-то вроде:

 DELETE FROM item WHERE n NOT IN 
     (SELECT i.n FROM item i INNER JOIN item_queue q ON i.n = q.n
      UNION SELECT i.n FROM item i INNER JOIN tool_queue t ON i.n = t.n)

Ваши коррелированные подзапросы выполняются по 10 000 раз каждый в вашем примере. Этот метод запускает два запроса INNER JOIN, чтобы получить список «n» для удаления.

Возможно, вам придется немного поиграться с SQL; Я не знаком с диалектом Оракула. ​​

1 голос
/ 16 марта 2010

Вы не можете получить хороший ответ на этот вопрос без дополнительной работы.

После выполнения самого оператора SQL наиболее важным является то, что статистика объектов (в данном случае таблиц и индексов) является репрезентативной.

Тогда вам действительно нужно взглянуть на путь доступа, который выбирает оракул - много способов сделать это.

Попробуйте

EXPLAIN PLAN SET STATEMENT_IS = 'SQL01' FOR
DELETE FROM item i 
 WHERE NOT EXISTS (SELECT 1 FROM item_queue q WHERE q.n=i.n) 
 AND NOT EXISTS (SELECT 1 FROM tool_queue t WHERE t.n=i.n);

Тогда

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

Возможно, опубликуйте результат здесь.

Если вы попробуете разные вещи, такие как переписывание запроса, изменение индексов и т. Д., Вы заметите, что путь доступа меняется.

Это довольно сложная область - и вам нужно будет учиться / практиковаться.

Удаление происходит медленно по ряду причин, но важным фактором является поддержание индексов в таблице. Однако, в вашем случае, вы говорите, что есть только 10 тыс. Строк, что довольно мало. (Кстати, вы не указали здесь время. Это занимает 1, 10 или 100 секунд в данный момент? И чего вы хотите достичь?) Поэтому я бы сосредоточился на пути доступа через большие таблицы.

Мой первый подход может быть:

DELETE FROM item i 
 WHERE NOT EXISTS 
(SELECT NULL
 FROM item_queue q,
      tool_queue g
  where q.key = g.key      -- if the tables are related
    AND q.n=i.n) ;

Но, как я уже сказал, здесь много факторов.

1 голос
/ 16 марта 2010

Убедитесь, что у вас нет ограничения на большую таблицу, которая ссылается на вашу таблицу элементов. Это может быть реальным замедлением в случае удалений.

1 голос
/ 16 марта 2010

Старайтесь избегать Subselect в ваших запросах и используйте INNER JOIN вместо

0 голосов
/ 16 марта 2010

Хотя это может быть не так быстро, было бы легче прочитать, если бы вы сделали:

DELETE FROM item i 
WHERE n NOT IN (SELECT n FROM item_queue)
AND n NOT IN (SELECT n FROM tool_queue)
0 голосов
/ 16 марта 2010

попробуйте использовать SELECT вместо delete, чтобы увидеть, действительно ли операция DELETE является узким местом

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...