mysql медленный запрос на выборку, пробовал каждый прием оптимизации, который я знаю! - PullRequest
1 голос
/ 20 апреля 2011

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

SELECT
    `date`,
    al.cost,
    SUM(l.bnd) AS bnd,
    l.type,
    count(*) AS amount
FROM alogs AS al
    INNER JOIN logs AS l ON al.logid = l.id
WHERE 
    aid = 0 AND
    l.`date` >= '2010-01-17' AND
    l.`date` <= '2011-04-19'
GROUP BY l.`date`, l.type

logs насчитывает 5 миллионов строк
alogs насчитывает 4,3 миллиона строк
время выполнения составляет около 90 секунд.

У меня есть:
первичный ключ на logs.id (auto inc)
индекс (BTREE) на logs.date
индекс (BTREE) на alogs.logid
индекс (BTREE) на alogs.aid

Я пытался:
- индекс (BTREE) для logs.type, но это ничего не улучшило (я думаю, потому что тип может быть только 2 вещами)
- индекс покрытия для журналов.date и logs.type
- внутреннее разбиение таблицы журналов по месяцам, но с указанным выше временным интервалом (который охватывал все разделы) он стал бы даже медленнее, не может разбить на части при помощи, поскольку существует более 2 000 различныхid
- удаление функций из запроса до тех пор, пока не станет быстро увидеть, в чем проблема.
Мне нужно было только удалить предложение GROUP (и функции SUM () и count (*) для получения правильных результатов)и таким образом время выполнения стало меньше секунды.
-удалите предложение group и group в памяти, но результат более 3 миллионов строк был слишком большим и занял бы больше времени.

Могу ли я сделать что-то еще, но я не знаю?Если так, я бы хотел услышать об этом!

Спасибо,

lordstyx

EDIT (2011-04-22 11:30) Вот результат EXPLAIN EXTENDED

id| select_type| table| type  | possible_keys| key    | key_len| ref     | rows   | Extra
1 | SIMPLE     | al   | ref   | logid,aid    | adid   | 4      | const   | 3010624| Using temporary; Using filesort
1 | SIMPLE     | l    | eq_ref| PRIMARY,date | PRIMARY| 4      | al.logid| 1      | Using where

Ответы [ 2 ]

0 голосов
/ 30 апреля 2011

, если фильтр aid обрезает большую часть строк, что-то вроде этого уменьшит данные, к которым присоединяются:

SELECT
    l.`date`,
    sum(al.cost) as cost,
    SUM(l.bnd) AS bnd,
    l.type,
    sum(qty) AS amount
FROM logs AS l
INNER JOIN
(
    SELECT logid, sum(cost) as cost, COUNT(*) as qty
    FROM alogs
    WHERE aid = 0
    GROUP BY logid
) al ON al.logid = l.id
GROUP BY l.`date`, l.type

Не зная немного больше о структуре данных (много alogs записей на logs запись?), Трудно предложить дальнейшие улучшения. Вычисление данных до объединений и предложений GROUP BY может значительно ускорить выполнение за счет сокращения общего количества строк, которые необходимо обработать. Поскольку запрос без группировки возвращает невероятно быстро, дальнейшее индексирование и настройка вряд ли увеличат скорость выполнения.

0 голосов
/ 22 апреля 2011

Если ваш диапазон дат представляет собой небольшой набор строк в таблице журнала, вы хотите, чтобы он использовал этот индекс.Вы сказали, что создали индекс для logs.date, но вам нужен составной индекс для (logs.date, logs.id), поэтому mysql не нужно читать строку с диска, чтобы получить идентификатор для присоединения к таблице alogs,Вы бы хотели индекс для alogs (log_id) для объединения.

Возможно, вы могли бы выжать еще немного, добавив столбцы из SELECT в индексы, так что

 logs(date, id, bnd, type)
 alogs(log_id, aid, cost)
...