У меня есть запрос:Почему запрос MySQL замедляется при использовании LIMIT с помощью Order BY?
SELECT abt.duration, a.id, a.a_id, a.a_tag
FROM active_begin_times AS abt INNER JOIN sources AS a ON a.id = abt.a_source
AND a.u IN (29, 28, 27, 26, 25, 24)
WHERE (abt.duration > 86400000)
and (abt.begin_timestamp<=1465185600000 and 1465617600000<=abt.end_timestamp
OR 1465185600000<=abt.begin_timestamp and abt.begin_timestamp<=1465617600000
OR 1465185600000<=abt.end_timestamp and abt.end_timestamp<=1465617600000)
order by abt.begin_timestamp asc LIMIT 0, 10
база данных имеет около 5 миллионов записей. Этот запрос занимает около 30 секунд. Но если я изменю, что я заказать столик в продолжительности, она рассчитывается в пределах доли секунды, как в запросе ниже:
SELECT abt.duration, a.id, a.a_id, a.a_tag
FROM active_begin_times AS abt INNER JOIN sources AS a ON a.id = abt.a_source
AND a.u IN (29, 28, 27, 26, 25, 24)
WHERE (abt.duration > 86400000)
and (abt.begin_timestamp<=1465185600000 and 1465617600000<=abt.end_timestamp
OR 1465185600000<=abt.begin_timestamp and abt.begin_timestamp<=1465617600000
OR 1465185600000<=abt.end_timestamp and abt.end_timestamp<=1465617600000)
order by abt.duration asc LIMIT 0, 10
У меня есть индексы на обоих продолжительности и на begin_timestamp. И когда я изменил порядок на abt.id, для вычисления снова потребовалось много времени, которое также имеет индексы.
Кроме того, что я заметил для этого конкретного набора условий, запрос возвращает 2 строки. Но если я изменю переменные, и я получаю этот запрос, чтобы вернуть от 20 до 30 нечетных строк, то вычисления будут мгновенными.
Не могли бы вы объяснить, что перечисленные выше 2 случая? Я пробовал смотреть в ТО, но не мог либо понять поведение, либо не был удовлетворен объяснением.
EXPLAIN
для первых возвращений запроса:
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
|----|-------------|-------|--------|----------------------------------------------------------|-----------------|---------|-----------------------|------|-------------|
| 1 | SIMPLE | abet | index | FK2681F9347A6A34B,begin_timestamp,end_timestamp,duration | begin_timestamp | 9 | \N | 6094 | Using where |
| 1 | SIMPLE | a | eq_ref | PRIMARY,FK722DBCA9F603AF | PRIMARY | 4 | db.abt.alarm_source | 1 | Using where |
А из второго запроса я получаю:
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
|----|-------------|-------|--------|----------------------------------------------------------|----------|---------|-----------------------|------|------------------------------------|
| 1 | SIMPLE | abet | range | FK2681F9347A6A34B,begin_timestamp,end_timestamp,duration | duration | 9 | \N | 8597 | Using index condition; Using where |
| 1 | SIMPLE | a | eq_ref | PRIMARY,FK722DBCA9F603AF | PRIMARY | 4 | db.abt.alarm_source | 1 | Using where |
Я видимое различие я вижу в Extras
столбцах, где в 2 запроса говорит Using index condition;
, бит, я не уверен, что с этим делать.
Выход SHOW CREATE TABLE active_begin_time:
CREATE TABLE active_begin_times (
id int(11) NOT NULL AUTO_INCREMENT,
begin_timezone_offset int(11) DEFAULT NULL,
begin_timezone_suffix varchar(100) DEFAULT NULL,
begin_timestamp bigint(20) DEFAULT NULL,
begin_timestamp_date varchar(100) DEFAULT NULL,
duration bigint(20) DEFAULT NULL,
end_timezone_offset int(11) DEFAULT NULL,
end_timezone_suffix varchar(100) DEFAULT NULL,
end_timestamp bigint(20) DEFAULT NULL,
end_timestamp_date varchar(100) DEFAULT NULL,
incomplete int(11) DEFAULT NULL,
a_source int(11) DEFAULT NULL,
PRIMARY KEY (id),
KEY FK2681F9347A6A34B (alarm_source),
KEY begin_timestamp (begin_timestamp),
KEY end_timestamp (end_timestamp),
KEY begin_timezone_offset (begin_timezone_offset),
KEY end_timezone_offset (end_timezone_offset),
KEY duration (duration),
KEY begin_timestamp_date (begin_timestamp_date),
KEY end_timestamp_date (end_timestamp_date)
) ENGINE=MyISAM AUTO_INCREMENT=6164640 DEFAULT CHARSET=latin1
Можете ли вы опубликовать вывод SHOW CREATE TABLE active_begin_times? – olegsv
только что обновил его. – rd22
Я бы предложил переписать запрос, используя BETWEEN: '(abt.end_timestamp BETWEEN 1465185600000 и 1465617600000)' – olegsv