Ускорить MYSQL запрос: заказ по дате - PullRequest
1 голос
/ 09 января 2020

У меня есть таблица с 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), как предлагалось в нескольких публикациях в блогах, но это тоже не сработало.

1 Ответ

0 голосов
/ 09 января 2020

Как вы уже сказали, вы используете MYSQL 8, который поддерживает нисходящий индекс, ПОСМОТРИТЕ этот индекс Проверьте производительность.

CREATE INDEX TABLE_NAME
ON Persons (updatedAt DESC,ownerId ASC );

Источник :

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