У меня есть таблица с 14000000 сообщений. Когда я запрашиваю таблицу с помощью оператора select, упорядоченного по полю даты и времени таблицы публикаций, MySQL всегда использует сортировку файлов, что приводит к очень медленному времени запроса (> 3 секунды). Вот схема таблицы истории (упрощенно):
+---------------------+---------------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------------+---------------------+------+-----+---------------------+----------------+
| Id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| parentId | bigint(20) unsigned | Yes | MUL | NULL | |
| ownerId | bigint(20) unsigned | NO | MUL | NULL | |
| updatedAt | timestamp(6) | Yes | MUL | CURRENT_TIMESTAMP(6)|DEFAULT_GENERATED|
| createdAt | timestamp(6) | Yes | MUL | CURRENT_TIMESTAMP(6)|DEFAULT_GENERATED|
| message | text | Yes | MUL | NULL | |
| imageUrl | varchar(255) | Yes | | NULL | |
+---------------------+---------------------+------+-----+---------------------+----------------+
Я также создаю индекс для ownerId
и updatedAt
, даже создаю составной индекс для (ownerId,updateAt)
с именем ownerId_updatedAt
. Вот таблица индексов:
+------------+------------+-------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+------------+------------+-------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| TABLE_NAME | 0 | PRIMARY | 1 | Id | A | 13457024 | NULL | NULL | | BTREE | | | YES | NULL |
| TABLE_NAME | 0 | Id_UNIQUE | 1 | Id | A | 13256858 | NULL | NULL | | BTREE | | | YES | NULL |
| TABLE_NAME | 1 | ownerId | 1 | ownerId | A | 899817 | NULL | NULL | | BTREE | | | YES | NULL |
| TABLE_NAME | 1 | updatedAt | 1 | updatedAt | A | 12862943 | NULL | NULL | YES | BTREE | | | YES | NULL |
| TABLE_NAME | 1 | ownerId_updatedAt | 1 | ownerId | A | 838060 | NULL | NULL | | BTREE | | | YES | NULL |
| TABLE_NAME | 1 | ownerId_updatedAt | 2 | updatedAt | A | 13457024 | NULL | NULL | YES | BTREE | | | YES | NULL |
+------------+------------+-------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
А вот запрос, выполнение которого занимает> 3 секунды. Число идентификаторов может быть большим до 100.
SELECT *
FROM TABLE_NAME
WHERE ownerId IN (id1,id2...,Idn)
AND updatedAt < COALESCE(
( SELECT updatedAt
FROM TABLE_NAME
WHERE storyId = 0),
CURRENT_TIMESTAMP )
AND privacy = 0
ORDER BY updatedAt DESC, ownerId ASC LIMIT 20;
Результат расширенная команда объяснения в этом запросе показывает, что MySQL использует файловую сортировку и использует условие индекса:
+----+-------------+------------+--------+---------------------------------------+-----------+---------+--------------------------+----------+----------+--------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered |Extra |
+----+-------------+------------+--------+---------------------------------------+-----------+---------+--------------------------+----------+----------+--------------------------------------------------+
| 1 | PRIMARY | TABLE_NAME | range | ownerId,updatedAt,ownerId_updatedAt | ownerId | 8 | NULL | 12792 | 5.00 |Using index condition;Using where; Using filesort |
+----+-------------+------------+--------+---------------------------------------+-----------+---------+--------------------------+----------+----------+--------------------------------------------------+
Когда я удаляю заказ по частям, MySQL прекращает использование файловой сортировки. Пожалуйста, дайте мне знать, если у вас есть идеи, как оптимизировать этот запрос, чтобы MySQL сортировал и выбирал данные с помощью индексов. Я уже пробовал несколько вещей, таких как создание комбинированного индекса для всех полей where / order по полям и использование FORCE INDEX(ownerId_updatedAt)
, как предлагалось в нескольких публикациях в блогах, но это тоже не сработало.