У меня есть таблица, в которой сейчас около 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 миллионов записей.

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

Спасибо.

1
Casteurr 8 Окт 2018 в 15:49

2 ответа

Лучший ответ

Думаю, 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. Это обычно не рекомендуется.

1
Gordon Linoff 8 Окт 2018 в 13:02

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

INDEX(status, created)

(Не болтайте о "мощности"; мы не смотрим на отдельные столбцы.)

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

PRIMARY KEY(status, created)

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

0
Rick James 9 Окт 2018 в 21:00