Производительность запроса SELECT

Модераторы: kdv, CyberMax

Ответить
Ingwar
Сообщения: 10
Зарегистрирован: 17 апр 2008, 18:20

Производительность запроса SELECT

Сообщение Ingwar » 03 май 2008, 12:10

Как можно ускорить выполнение запроса:

Код: Выделить всё

SELECT ID FROM TOVARY WHERE NOT ID IN
(SELECT T_ID FROM STORAGE UNION
SELECT T_ID FROM INDETAILS UNION
SELECT T_ID FROM OUTDETAILS)
Индексы по полям T_ID в таблицах STORAGE, INDETAILS, OUTDETAILS существуют.
Последний раз редактировалось Ingwar 04 май 2008, 23:09, всего редактировалось 1 раз.

Esperito
Сообщения: 10
Зарегистрирован: 09 авг 2007, 19:23

Сообщение Esperito » 03 май 2008, 17:16

Попробуй использовать EXISTS вместо IN.

Ingwar
Сообщения: 10
Зарегистрирован: 17 апр 2008, 18:20

Сообщение Ingwar » 04 май 2008, 09:34

Вопрос решен так:

Код: Выделить всё

SELECT T.ID, T.NAME, US.T_ID
FROM TOVARY T
LEFT OUTER JOIN (SELECT T_ID FROM STORAGE UNION
   SELECT T_ID FROM INDETAILS UNION
   SELECT T_ID FROM OUTDETAILS) US
  ON US.T_ID=T.ID
WHERE US.T_ID IS NULL
Производительность почти в 500 раз выше (120 мс вместо 1 мин на существующей БД).
Источник: http://www.az-design.ru/Support/DataBas ... 0002.shtml

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 04 май 2008, 12:49

А вот и плохо вопрос решён.
Правильно писать так:

Код: Выделить всё

SELECT T.ID, T.NAME, US.T_ID 
  FROM TOVARY T
  WHERE NOT EXISTS
(
  SELECT T_ID FROM STORAGE
  UNION ALL
  SELECT T_ID FROM INDETAILS
  UNION ALL
  SELECT T_ID FROM OUTDETAILS
)
Найди два отличия.

ЗЫ: А тому "источнику" надо идти букварь читать. Про оптимизацию NOT IN разными серверами, а также про NOT EXISTS, и как он реализован в различных серверах. Не написано даже, на каком сервере тест проводил. А ведь некоторые умеют даже данные не читать (индексное чтение), а ограничиваться _только_ чтением индекса.

hvlad
Разработчик Firebird
Сообщения: 1244
Зарегистрирован: 21 мар 2005, 10:48

Сообщение hvlad » 04 май 2008, 13:04

WildSery писал(а):А вот и плохо вопрос решён.
Правильно писать так:

Код: Выделить всё

SELECT T.ID, T.NAME, US.T_ID 
  FROM TOVARY T
  WHERE NOT EXISTS
(
  SELECT T_ID FROM STORAGE
  UNION ALL
  SELECT T_ID FROM INDETAILS
  UNION ALL
  SELECT T_ID FROM OUTDETAILS
)
Найди два отличия.
WHERE кто писать будет ?

Ingwar
Сообщения: 10
Зарегистрирован: 17 апр 2008, 18:20

Сообщение Ingwar » 04 май 2008, 13:34

WildSery писал(а):А вот и плохо вопрос решён.
Правильно писать так:

Код: Выделить всё

SELECT T.ID, T.NAME, US.T_ID 
  FROM TOVARY T
  WHERE NOT EXISTS
(
  SELECT T_ID FROM STORAGE
  UNION ALL
  SELECT T_ID FROM INDETAILS
  UNION ALL
  SELECT T_ID FROM OUTDETAILS
)
В приведенном тобой запросе используется US.T_ID, но в моем запросе US- обозначение комплексного UNION. У тебя же его нет, потому, я так понимаю, колонку US.T_ID нужно вообще удалить из запроса.

Тогда твой запрос у меня постоянно возвращает пустой набор, то есть не делает чего надо.

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 04 май 2008, 13:53

Влад верно сказал. Это я ещё кофе не попил.
Вот, поправил:

Код: Выделить всё

SELECT T.ID, T.NAME
  FROM TOVARY T 
  WHERE NOT EXISTS 
( 
  SELECT T_ID FROM STORAGE WHERE T_ID = T.ID
  UNION ALL 
  SELECT T_ID FROM INDETAILS WHERE T_ID = T.ID
  UNION ALL 
  SELECT T_ID FROM OUTDETAILS WHERE T_ID = T.ID
)

Ingwar
Сообщения: 10
Зарегистрирован: 17 апр 2008, 18:20

Сообщение Ingwar » 04 май 2008, 15:11

WildSery писал(а):Влад верно сказал. Это я ещё кофе не попил.
Вот, поправил...
Да, спасибо, работает все супер. И приблизительно в 10 раз быстрее предложенного ранее мной варианта.

И еще: почему мой исходный запрос работает так ужасающе медленно? Где можно почитать об етом?

Attid
Спец
Сообщения: 377
Зарегистрирован: 14 ноя 2006, 09:58

Сообщение Attid » 04 май 2008, 15:21

Ingwar писал(а): И еще: почему мой исходный запрос работает так ужасающе медленно?
условие where если мне не изменяет склероз выполняется на каждую запись чтоб определить есть там входящие записи, соответственно твой подзапрос выполняется пусть даже всего 1 секунду, будет выполняться столько раз сколько записей в товарах , и если их там хотябы 100 то выполнение всего запроса будет идти уже полторы минуты.

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 04 май 2008, 16:11

Ingwar писал(а):Где можно почитать об етом?
Думаю, лучше всего статью Дмитрия Еманова о способах доступа.
Медленность в том, что рекурсивный перебор (читай в статье) усугублён дополнительно UNION.
План запроса скорее всего NATURAL для вложенных таблиц? Т.е. на каждый код из TOVARY выполняется объединение из трёх таблиц целиком!

Ingwar
Сообщения: 10
Зарегистрирован: 17 апр 2008, 18:20

Сообщение Ingwar » 04 май 2008, 16:44

Спасибо всем кто откликнулся (и особенно WildSery)- проблема решилась :)

Gera
Сообщения: 53
Зарегистрирован: 12 мар 2008, 17:34

Сообщение Gera » 29 май 2008, 11:42

Прошу прощения за столь поздний пост - раньше времени небыло
провел некоторое тестирование и по результатам запрос вида

Код: Выделить всё

SELECT T.ID, T.NAME
  FROM TOVARY T
  WHERE NOT EXISTS (SELECT T_ID FROM STORAGE WHERE T_ID = T.ID)
    AND NOT EXISTS (SELECT T_ID FROM INDETAILS WHERE T_ID = T.ID)
    AND NOT EXISTS (SELECT T_ID FROM OUTDETAILS WHERE T_ID = T.ID)
)
дал наименьшее время выполнения.
PS порядок таблиц также влияет на скорость. первой должна идти та, в которой наибольшая вероятность наличия записи

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 29 май 2008, 12:37

Gera писал(а):PS порядок таблиц также влияет на скорость. первой должна идти та, в которой наибольшая вероятность наличия записи
Порядок проверки предикатов, насколько я знаю, стохастический и зависит от конкретной структуры запроса.
Потому для каждого запроса надо уточнять, какой выполняется первым.

Ответить