SQLinfo.ru - Все о MySQL

Форум пользователей MySQL

Задавайте вопросы, мы ответим

Вы не зашли.

#1 27.05.2017 17:51:52

freeds
Участник
Зарегистрирован: 27.05.2017
Сообщений: 4

Диапазон, group by, Using temporary

Есть с виду простейшая задача, которую не могу решить.

Есть таблица, 3 колонки. Нужно выбрать срез по времени и сгруппировать по колонке hash. Проблема в том, что если используется ключ hash, то перебираются все записи, вне зависимости от среза по времени. Если использовать составной индекс (ctime, hash), то используется только часть индекса + создается временная таблица.

В итоге нужно сделать группировку по срезу времени без использования временной таблицы (Using temporary). Увы, у меня не получается


CREATE TABLE `_table` (
    `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    `hash` VARCHAR(32) NOT NULL,
    `ctime` INT(10) UNSIGNED NOT NULL DEFAULT '0',
    PRIMARY KEY (`id`),
    INDEX `ctime` (`ctime`),
    INDEX `hash` (`hash`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;

SELECT `hash` FROM `_table` WHERE `ctime` > 1490979600 and `ctime` < 1495904399 GROUP BY `hash` ORDER BY null;

Неактивен

 

#2 27.05.2017 20:21:48

deadka
Администратор
Зарегистрирован: 14.11.2007
Сообщений: 2420

Re: Диапазон, group by, Using temporary

Выбирать здесь данные "чисто" по индексу не получится при такой постановке задачи.
Если бы выбирали WHERE `ctime` = 1490979600 GROUP BY `hash`, то хорошо бы себя повел составной индекс (`ctime`,`hash`). Но тут условие < > - так что вторая часть индекса не будет использоваться.

В итоге нужно сделать группировку по срезу времени без использования временной таблицы
А что значит нужно? Кому нужно? Расскажите подробнее. Иначе задача нерешаема. Единственное, что приходит в голову (это если у Вас детерменированные интервалы на ctime, допустим, в пределах дня) - добавить еще одно денормализованное поле, которое содержит дату, или час или еще что - и с ним уже построить составной индекс.

А при текущем запросе по хорошему нужно использовать индекс по полю ctime и это будет оптимально. Можно подсказать оптимизатору, чтобы он его и использовал ( use index, force index, ignore index )


Зеленый свет для слабаков, долги отдают только трусы, тру гики работают только в консоли...

Неактивен

 

#3 28.05.2017 00:56:35

freeds
Участник
Зарегистрирован: 27.05.2017
Сообщений: 4

Re: Диапазон, group by, Using temporary

deadka написал:

А что значит нужно? Кому нужно? Расскажите подробнее. Иначе задача нерешаема.

В таблице порядка 20 млн записей. В выборку за день попадает примерно 60к записей

deadka написал:

А при текущем запросе по хорошему нужно использовать индекс по полю ctime и это будет оптимально. Можно подсказать оптимизатору, чтобы он его и использовал ( use index, force index, ignore index )

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

Неактивен

 

#4 28.05.2017 09:37:09

deadka
Администратор
Зарегистрирован: 14.11.2007
Сообщений: 2420

Re: Диапазон, group by, Using temporary

>Либо используется индекс по полю ctime, но из-за группировки перебираются все записи.
Не все, а только те, что выбраны по индексу.
Покажите explain запроса.


Зеленый свет для слабаков, долги отдают только трусы, тру гики работают только в консоли...

Неактивен

 

#5 28.05.2017 21:27:32

freeds
Участник
Зарегистрирован: 27.05.2017
Сообщений: 4

Re: Диапазон, group by, Using temporary

deadka написал:

>Либо используется индекс по полю ctime, но из-за группировки перебираются все записи.
Не все, а только те, что выбраны по индексу.
Покажите explain запроса.

mysql> explain select `hash` from `_table` where `ctime` > 1495176217 and `ctime
` < 1495817157 group by hash order by null\G;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: _table
         type: range
possible_keys: ctime,ctime_hash,hash
          key: ctime_hash
      key_len: 4
          ref: NULL
         rows: 14
        Extra: Using where; Using index; Using temporary

В этом запросе да, используется половина составного индекса - ctime. В таблице 30 записей, выбралось 14. При этом из-за группировки создается временная таблица. Это не приемлемо с результатами выборки в миллионах.
Согласен на любые предложения.

Неактивен

 

#6 29.05.2017 12:28:14

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6756

Re: Диапазон, group by, Using temporary

К сожалению, в жизни нету магии. Индекс — это аналог телефонного справочника, где hash — имя человека, а ctime — его телефоны. И аналог Вашего запроса — «покажите мне все телефоны людей, сгруппированных по имени, телефоны которых начинаются с +7495».

Вы можете или держать книгу сортированных имен (и тогда вынуждены внутри имен полным сканом смотреть телефоны), или иметь книгу всех телефонов (и тогда вынуждены внутри нужного диапазона телефонов отдельно выписывать имена пользователей).


Что делать? Пересмотреть задачу. Я бы думал в сторону денормализации.
Идея раз. Почти наверняка Вам нужны не любые диапазоны ctime, а только некоторые. Тогда можно сделать отдельную табличку с hash, попадающую в нужные диапазоны.
Идея два. Почти наверняка многие hash приходят только раз, а потом больше не участвуют в игре. Тогда можно сделать табличку (hash, min_ctime, max_ctime) и проверять заранее, попадает ли хэш в принципе в диапазон. А для найденных hash уже проверять честные вхождения по большой таблице.

Неактивен

 

#7 29.05.2017 22:30:28

freeds
Участник
Зарегистрирован: 27.05.2017
Сообщений: 4

Re: Диапазон, group by, Using temporary

paulus написал:

Вы можете или держать книгу сортированных имен (и тогда вынуждены внутри имен полным сканом смотреть телефоны), или иметь книгу всех телефонов (и тогда вынуждены внутри нужного диапазона телефонов отдельно выписывать имена пользователей).

Да, вот об этом я и говорил, что Или Или.

paulus написал:

Что делать? Пересмотреть задачу. Я бы думал в сторону денормализации.
Идея раз. Почти наверняка Вам нужны не любые диапазоны ctime, а только некоторые. Тогда можно сделать отдельную табличку с hash, попадающую в нужные диапазоны.
Идея два. Почти наверняка многие hash приходят только раз, а потом больше не участвуют в игре. Тогда можно сделать табличку (hash, min_ctime, max_ctime) и проверять заранее, попадает ли хэш в принципе в диапазон. А для найденных hash уже проверять честные вхождения по большой таблице.

В принципе, я ожидал, что решений в "одну" строчку не будет. Ваши идеи весьма привлекательны, спасибо за подсказку!
Тему считаю закрытой.

Неактивен

 

Board footer

Работает на PunBB
© Copyright 2002–2008 Rickard Andersson