Почему мой многоколонный запрос значительно медленнее, чем соответствующий одноколонный запрос, даже с многоколоночным индексом? - PullRequest
1 голос
/ 22 ноября 2011

У меня следующий запрос:

SELECT * 
from stop_times 
WHERE (departure_time BETWEEN '02:41' AND '05:41' 
       OR departure_time BETWEEN '26:41' AND '29:41') 
    AND stop_times.stop_id IN(51511,51509,51508,51510,6,53851,51522,51533)

, который возвращает 134 строки в ~ 800 мс.Если я разделю его:

SELECT * 
from stop_times 
WHERE (departure_time BETWEEN '02:41' AND '05:41' 
       OR departure_time BETWEEN '26:41' AND '29:41')

возвращает ~ 110 тыс. Строк за ~ 10 мс, а

SELECT * 
from stop_times 
WHERE stop_times.stop_id IN(51511,51509,51508,51510,6,53851,51522,51533)

возвращает ~ 5 тыс. Строк за ~ 100 мс.

Я попытался использовать обамногостолбцовый индекс (выезд-время и стоп-идентификатор), а также 2 отдельных индекса, но в любом случае первый запрос не может занять менее ~ 800 мс.Моя таблица stop_times содержит около 3,5 миллионов строк.Могу ли я что-то упустить, и это значительно ускорит этот первый запрос?

ОБНОВЛЕНИЕ 1: ПОКАЗАТЬ СОЗДАНИЕ ТАБЛИЦЫ:

CREATE TABLE `stop_times` (
  `trip_id` varchar(20) DEFAULT NULL,
  `departure_time` time DEFAULT NULL,
  `stop_id` varchar(20) DEFAULT NULL,
  KEY `index_stop_times_on_trip_id` (`trip_id`),
  KEY `index_stop_times_on_departure_time_and_stop_id` (`departure_time`,`stop_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

stop_id и trip_id - varcharsвместо целых чисел, к сожалению, вне моего контроля ...

ОБНОВЛЕНИЕ 2: EXPLAIN для departure_time, stop_id многостолбцовый индекс:

select_type: SIMPLE
type: range
rows: 239084

EXPLAINдля stop_id, departure_time многостолбцовый индекс:

select_type: SIMPLE
type: range
rows: 141

ОБНОВЛЕНИЕ 3: EXPLAIN для IN(51511,51509,51508,51510,6,53851,51522,51533)

select_type: SIMPLE
type: ALL
rows: 3556973 (lol)

EXPLAIN для IN("51511","51509","51508","51510","6","53851","51522","51533")

select_type: SIMPLE
type: range
rows: 141

Ответы [ 2 ]

3 голосов
/ 22 ноября 2011

Вы создали индекс stop_id, departure_time? Потому что departure_time, stop_id абсолютно ничего не сделает.

Это действительно сложный - у него есть все возможные плохие вещи для работы с индексами: (

У вас есть диапазон, ИЛИ и несмежный IN - хуже не будет.

Попробуйте stop_id, departure_time, и если это не поможет, вы ничего не сможете сделать, кроме как переключиться на PostgreSQL.


Вы также можете попробовать переписать запрос следующим образом:

SELECT * 
from stop_times 
WHERE ( stop_times.stop_id IN(51511,51509,51508,51510,6,53851,51522,51533)
      AND departure_time BETWEEN '02:41' AND '05:41'
      )
   OR ( stop_times.stop_id IN(51511,51509,51508,51510,6,53851,51522,51533)
      AND departure_time BETWEEN '26:41' AND '29:41' 
      ) 

или

    SELECT * 
    from stop_times 
    WHERE ( stop_times.stop_id IN(51511,51509,51508,51510,6,53851,51522,51533)
          AND departure_time BETWEEN '02:41' AND '05:41'
          )
UNION ALL
    SELECT * 
    from stop_times 
    WHERE ( stop_times.stop_id IN(51511,51509,51508,51510,6,53851,51522,51533)
          AND departure_time BETWEEN '26:41' AND '29:41' 
          )
0 голосов
/ 22 ноября 2011

Существует одна возможность, которую вы можете попробовать: сначала подготовить список всех времен, которые происходят в обоих диапазонах, а затем соединить их в большое предложение IN - это может выглядеть ужасно, но удалитусловие OR, которое не помогает вашему запросу ... И вы сможете построить строку IN, используя ваш любимый язык программирования:)

WHERE departure_time IN ('02:41','02:42','02:43', ... '26:41','26:42','26:43', ... etc )

Ваш запрос содержит два блока по тричасов, что соответствует 6 * 60 = 360 записей в предложении IN ...

Стоит попробовать хотя бы ...

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