Как использовать ограничение в запросе к моему столбцу индекса без сканирования всех строк? - PullRequest
0 голосов
/ 17 ноября 2018

Вот моя таблица:

enter image description here

В моей таблице

  • Clustering_key (Первичный ключ и автоинкрементный))
  • ID (столбец индекса)
  • Data (столбец типа текста)
  • Position (столбец индекса) поддерживает порядок Data

В моей таблице 90 000 строк с одинаковыми ID, равными 5. Я хочу первые 3 строки с ID, равными 5, и мой запрос выглядит так

Select * from mytable where ID=5 Limit 3;

ID column является столбцом индекса. Так что я думаю, что mysql сканирует только первые 3 строки, но mysql сканирует около 42000 строк.

Здесь Объясните запрос:

enter image description here

Любая возможность избежать сканирования всех строк.

Пожалуйста, дайте мне какое-нибудь решение

Заранее спасибо

1 Ответ

0 голосов
/ 26 апреля 2019

Я смоделировал сценарий.

  • Создана таблица с использованием

   CREATE TABLE mytable (
        Clustering_key INT NOT NULL AUTO_INCREMENT,
        ID INT NOT NULL,
        Data text NOT NULL,
        Position INT NOT NULL,
        PRIMARY KEY (Clustering_key),
        KEY(ID),
        KEY(Position)
    )

  • Вставленные данные с

    INSERT INTO mytable (ID,Data,Position) VALUES (5,CONCAT("Data-",5), 7);
    INSERT INTO mytable (ID,Data,Position) VALUES (5,CONCAT("Data-",5), 26);
    INSERT INTO mytable (ID,Data,Position) VALUES (5,CONCAT("Data-",51), 27);
    INSERT INTO mytable (ID,Data,Position) VALUES (5,CONCAT("Data-",56), 28);
    INSERT INTO mytable (ID,Data,Position) VALUES (5,CONCAT("Data-",57), 31);

  • Объясните

    mysql> explain Select * from mytable where ID=5 Limit 3
    +----+-------------+---------+------------+------+---------------+------+---------+-------+------+----------+-------+
    | id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref   | rows | filtered | Extra |
    +----+-------------+---------+------------+------+---------------+------+---------+-------+------+----------+-------+
    |  1 | SIMPLE      | mytable | NULL       | ref  | ID            | ID   | 4       | const |    5 |   100.00 | NULL  |
    +----+-------------+---------+------------+------+---------------+------+---------+-------+------+----------+-------+
    1 row in set, 1 warning (0.00 sec)

Да, explain показывает проверенные строки 5, но не 3. Но, похоже, это просто вводящая в заблуждение информация. Точное количество строк row_examined во время выполнения можно проверить, включив медленный журнал для всех запросов (установка long_query_time = 0), выполнив следующие действия.

Примечание: вы ДОЛЖНЫ установить long_query_time = 0 только в своей собственной тестовой базе данных. И вы ДОЛЖНЫ сбросить параметр обратно к предыдущему значению после тестирования.


     - set GLOBAL slow_query_log=1;
     - set global long_query_time=0;
     - set session long_query_time=0;
     mysql> show variables like '%slow%';
    +---------------------------+-------------------------------------------------+
    | Variable_name             | Value                                           |
    +---------------------------+-------------------------------------------------+
    | log_slow_admin_statements | OFF                                             |
    | log_slow_slave_statements | OFF                                             |
    | slow_launch_time          | 2                                               |
    | slow_query_log            | ON                                              |
    | slow_query_log_file       | /usr/local/mysql/data/slow.log                  |
    +---------------------------+-------------------------------------------------+
    5 rows in set (0.10 sec)
    mysql> select @@long_query_time;
    +-------------------+
    | @@long_query_time |
    +-------------------+
    |          0.000000 |
    +-------------------+
    
And then in the terminal, executing the query
<pre>
mysql> Select * from mytable where ID=5 Limit 3;
+----------------+----+---------+----------+
| Clustering_key | ID | Data    | Position |
+----------------+----+---------+----------+
|              5 |  5 | Data-5  |        7 |
|          26293 |  5 | Data-5  |       26 |
|          26294 |  5 | Data-51 |       27 |
+----------------+----+---------+----------+
3 rows in set (0.00 sec)

mysql> Select * from mytable where ID=5 Limit 1;

Проверка медленного журнала путем проверки slow_query_log_file, напечатанного выше /usr/local/mysql/data/slow.log

Вы можете узнать информацию, как показано ниже.


    # Time: 2019-04-26T01:48:19.890846Z
    # User@Host: root[root] @ localhost []  Id:  5124
    # Query_time: 0.000575  Lock_time: 0.000146 Rows_sent: 3  Rows_examined: 3 
    SET timestamp=1556243299;
    Select * from mytable where ID=5 Limit 3;
    # Time: 2019-04-26T01:48:34.672888Z
    # User@Host: root[root] @ localhost []  Id:  5124
    # Query_time: 0.000182  Lock_time: 0.000074 Rows_sent: 1  Rows_examined: 1 
    SET timestamp=1556243314;
    Select * from mytable where ID=5 Limit 1;

Значение времени выполнения Rows_exmained равно значению параметра limit. Тест выполнен на MySQL 5.7.18.

---------------------------------- Еще один способ проверки --------- -------------------------



    mysql> show status like '%Innodb_rows_read%';
    +------------------+-------+
    | Variable_name    | Value |
    +------------------+-------+
    | Innodb_rows_read | 13    |
    +------------------+-------+
    1 row in set (0.00 sec)

    mysql> Select * from mytable where ID=5 Limit 1;
    +----------------+----+--------+----------+
    | Clustering_key | ID | Data   | Position |
    +----------------+----+--------+----------+
    |              5 |  5 | Data-5 |        7 |
    +----------------+----+--------+----------+
    1 row in set (0.00 sec)

    mysql> show status like '%Innodb_rows_read%';
    +------------------+-------+
    | Variable_name    | Value |
    +------------------+-------+
    | Innodb_rows_read | 14    |
    +------------------+-------+
    1 row in set (0.00 sec)

Вы можете видеть Innodb_rows_read просто увеличенным на 1 для лимита 1. Если вы выполните запрос полной проверки таблицы, вы увидите, что значение будет увеличено на счет таблицы.


    mysql> select count(*) from mytable;
    +----------+
    | count(*) |
    +----------+
    |   126296 |
    +----------+
    1 row in set (0.05 sec)

    mysql> show status like '%Innodb_rows_read%';
    +------------------+--------+
    | Variable_name    | Value  |
    +------------------+--------+
    | Innodb_rows_read | 505204 |
    +------------------+--------+
    1 row in set (0.00 sec)

    mysql> Select * from mytable where Data="Data-5";
    +----------------+----+--------+----------+
    | Clustering_key | ID | Data   | Position |
    +----------------+----+--------+----------+
    |              5 |  5 | Data-5 |        7 |
    |          26293 |  5 | Data-5 |       26 |
    |          26301 |  5 | Data-5 |        7 |
    +----------------+----+--------+----------+
    3 rows in set (0.09 sec)

    mysql> show status like '%Innodb_rows_read%';
    +------------------+--------+
    | Variable_name    | Value  |
    +------------------+--------+
    | Innodb_rows_read | 631500 |
    +------------------+--------+
    1 row in set (0.00 sec)

Оба способа подтвердили, что explain для лимита предоставляет вводящую в заблуждение информацию о проверенных строках.

...