Не все индексы одинаково полезны
Имеется InnoDB табличка, небольшая - меньше миллиона записей, делаем такой запрос (нужно получить top10 доменов):
> select dlvDestinationDomain, count(*) from email_accounting where jobid="11837" group by dlvDestinationDomain order by count(*) desc limit 10
созданы следующие индексы:
| PRIMARY | BTREE | id |
|---|---|---|
| jobId | BTREE | jobId |
| dlvDestinationDomain | BTREE | dlvDestinationDomain |
| dlvDestinationDomain_2 | BTREE | dlvDestinationDomain |
| A | ||
| jobId_3 | BTREE | jobId |
| A |
Обнаружилась забавная вещь: некоторые индексы не только не ускоряют но и замедляют агрегатные запросы:
вообще без использования индексов:
mysql> select dlvDestinationDomain, count(*) from email_accounting IGNORE INDEX(dlvDestinationDomain_2, jobId_3, jobId, dlvDestinationDomain) where jobid="11837" group by dlvDestinationDomain order by count(*) desc limit 10;
3.09 секунды
используя индекс по jobId дает небольшой прирост производительности:
mysql> select dlvDestinationDomain, count(*) from email_accounting FORCE INDEX (jobId) where jobid="11837" group by dlvDestinationDomain order by count(*) desc limit 10;
2.13 секунд;
использование составного индекса по jobID и dlvDestinationDomain сделало все гораздо веселее:
mysql> select dlvDestinationDomain, count(*) from email_accounting FORCE INDEX (jobId_3) where jobid="11837" group by dlvDestinationDomain order by count(*) desc limit 10;
0.39 секунд;
ипользование ключа с полям в обратном порядке (dlvDestinationDomain и jobID) работает гораздо хуже:
mysql> select dlvDestinationDomain, count(*) from email_accounting FORCE INDEX (dlvDestinationDomain_2) where jobid="11837" group by dlvDestinationDomain order by count(*) desc limit 10;
1.36 секунд;
А вот использование ключа только по dlvDestinationDomain заставляет MySQL думать почти две минуты:
mysql> select dlvDestinationDomain, count(*) from email_accounting FORCE INDEX (dlvDestinationDomain) where jobid="11837" group by dlvDestinationDomain order by count(*) desc limit 10;
1 минута 48 секунд;
Кстати, заметил, что использование jobid="11837" (jobid у меня текстовое) заметно прибавляет скорости против jobid=11837. Не зря в strict моде MySQL грязно ругается на такие преобразования, ох не зря...
Upd. Во всем оказались замешаны настройки InnoDB, если увеличить в my.cnf значение переменной innodb_buffer_pool_size то скорость выполнения агрегативного запроса с индексом по группируемому полю заметно возрастает и картина меняется на прямо противоположную.
О свободе слова в Интернет
Вчера рассказали изумительный стишок:
Товарищ верь, пройдет она,
И демократия и гласность,
Но Комитет Госбезопасность,
Запомнит ваши имена!
Покатался с горки
Сегодня сходил покатался с горки на Первой Дачной, всего за этот год это получился уже четвертый раз когда я выбрался покататься. Катался на горнолыжной базе "Роща".
В прошлые разы немного поснимал телефоном, и наконец, смонтировал то что получилось:
Функция преобразования даты из ISO 8601
Потребовалось обработать логи в которых дата хранилась примерно в таком формате 2010-12-03T18:34:33-0500. К сожалению в PHP нет толковой функции для преобразования строкового представления даты в timestamp. Как показала практика strtodate совершенно не учитывает последние четыре знака в строке которые она просто отбрасывет.
Пришлось парсерить строчку ручками и вот что получилось:
function covertdate($date){
preg_match('/(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})([-+])(\d{2})(\d{2})/', $date,$res);
list($d,$year,$month,$day,$hour,$minute,$second,$digit,$zonehours,$zoneminutes) = $res;
$offset = ((int)($digit."1"))*($zonehours*3600+$zoneminutes*60);
$timestamp = gmmktime($hour,$minute,$second,$month,$day,$year)-$offset;
return $timestamp;
}