Оптимизация MySQL-запроса с составным индексом - PullRequest
0 голосов
/ 08 октября 2018

У меня есть таблица, которая в настоящее время насчитывает около 80 миллионов строк, созданных следующим образом:

create table records
(
  id      int auto_increment primary key,
  created int             not null,
  status  int default '0' not null
)
  collate = utf8_unicode_ci;

create index created_and_status_idx
  on records (created, status);

Созданный столбец содержит метки времени Unix, а состояние может быть целым числом от -10 до 10. Записи равномернораспределено относительно даты создания, и около половины из них имеют статус 0 или -10.

У меня есть cron, который выбирает записи, которые имеют возраст от 32 до 8 дней, обрабатывает их, а затем удаляет их, навернякастатусы.Запрос выглядит следующим образом:

SELECT
    records.id
FROM records
WHERE
    (records.status = 0 OR records.status = -10)
    AND records.created BETWEEN UNIX_TIMESTAMP() - 32 * 86400 AND UNIX_TIMESTAMP() - 8 * 86400
LIMIT 500

Запрос был быстрым, когда записи находились в начале интервала создания, но теперь, когда очистка достигает записей в конце интервала, требуется около 10 секунд, чтобызапустить.В объяснении запроса говорится, что он использует индекс, но анализирует около 40 миллионов записей.

У меня вопрос, есть ли что-нибудь, что я могу сделать, чтобы улучшить производительность запроса, и если да, то как именно.

Спасибо.

Ответы [ 2 ]

0 голосов
/ 10 октября 2018

Ваш индекс в неправильном порядке.Вы должны поставить столбец IN (status) первым (вы назвали его OR), а столбец 'range' (created) последним:

INDEX(status, created)

(Донне говорите мне что-нибудь о "кардинальности", мы не смотрим на отдельные столбцы.)

В таблице действительно только 3 столбца?Вам нужно id?Если нет, то избавьтесь от него и измените на

PRIMARY KEY(status, created)

Другие методы для эффективной прогулки по большим столам.

0 голосов
/ 08 октября 2018

Я думаю, union all - ваш лучший подход:

(SELECT r.id
 FROM records r
 WHERE r.status = 0 AND
       r.created BETWEEN UNIX_TIMESTAMP() - 32 * 86400 AND UNIX_TIMESTAMP() - 8 * 86400
 LIMIT 500
) UNION ALL
(SELECT r.id
 FROM records r
 WHERE r.status = -10 AND
       r.created BETWEEN UNIX_TIMESTAMP() - 32 * 86400 AND UNIX_TIMESTAMP() - 8 * 86400
 LIMIT 500
) 
LIMIT 500;

Это может использовать индекс для records(status, created, id).Примечание: используйте union, если records.id может иметь дубликаты.

Вы также используете LIMIT без ORDER BY.Это вообще не рекомендуется.

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