如何在我的索引列上使用限制查询而不扫描所有行?

Shu*_*ham 7 mysql database innodb

这是我的表:

在此输入图像描述

在我的桌子上

  • Clustering_key (主键和自动增量)
  • ID (索引栏)
  • Data (文本数据类型列)
  • Position(索引列)维持的顺序 Data

我的表有90,000行,相同ID等于5.我想前3行ID等于5,我的查询是这样的

Select * from mytable where ID=5 Limit 3;
Run Code Online (Sandbox Code Playgroud)

ID 列是索引列所以我认为mysql只扫描前3行但mysql扫描大约42000行.

这里解释查询:

在此输入图像描述

任何可能避免所有行扫描.

请给我一些解决方案

提前致谢

Pop*_*eye 3

我模拟了这个场景。

  • 使用创建表
   创建表 mytable (
        Clustering_key INT NOT NULL AUTO_INCRMENT,
        ID INT 不为空,
        数据文本不为空,
        位置 INT NOT NULL,
        主键(聚类键),
        密钥(ID),
        按键(位置)
    )

  • 插入的数据与
    INSERT INTO mytable (ID,数据,位置) VALUES (5,CONCAT("数据-",5), 7);
    INSERT INTO mytable (ID,数据,位置) VALUES (5,CONCAT("数据-",5), 26);
    INSERT INTO mytable (ID,数据,位置) VALUES (5,CONCAT("数据-",51), 27);
    INSERT INTO mytable (ID,数据,位置) VALUES (5,CONCAT("数据-",56), 28);
    INSERT INTO mytable (ID,数据,位置) VALUES (5,CONCAT("数据-",57), 31);

  • 解释
    mysql> 解释 Select * from mytable where ID=5 Limit 3
    +----+-------------+---------+------------+-----+ ---------------+------+---------+--------+--------+-- --------+--------+
    | 编号 | 选择类型 | 表| 隔断| 类型 | 可能的键 | 关键| key_len | 参考| 行 | 过滤| 额外 |
    +----+-------------+---------+------------+-----+ ---------------+------+---------+--------+--------+-- --------+--------+
    | 1 | 简单| 我的表 | 空 | 参考| 身份证 | 身份证 | 4 | 常量 | 5 | 100.00 | 空 |
    +----+-------------+---------+------------+-----+ ---------------+------+---------+--------+--------+-- --------+--------+
    1 行一组,1 次警告(0.00 秒)

是的,explain显示检查的行数是 5,而不是 3。但这似乎只是一个误导性信息。可以通过以下步骤为所有查询启用慢速日志(设置 long_query_time=0)来验证运行时 rows_examined 的确切数量。

注意:您必须仅在您自己的测试数据库中设置 long_query_time=0。并且测试后必须将参数重置回之前的值。

     - 设置全局slow_query_log=1;
     - 设置全局long_query_time=0;
     - 设置会话long_query_time=0;
     mysql> 显示类似“%slow%”的变量;
    +-------------------------+--------------------- ----------------------------+
    | 变量名 | 价值|
    +-------------------------+--------------------- ----------------------------+
    | log_slow_admin_statements | 日志慢速管理语句 关闭 |
    | log_slow_slave_statements | log_slow_slave_statements | 关闭 |
    | 慢启动时间 | 2 |
    | 慢速查询日志 | 开 |
    | 慢速查询日志文件 | /usr/local/mysql/data/slow.log | /usr/local/mysql/data/slow.log |
    +-------------------------+--------------------- ----------------------------+
    5 行一组(0.10 秒)
    mysql> 选择@@long_query_time;
    +--------------------+
    | @@long_query_time |
    +--------------------+
    | 0.000000 | 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;
Run Code Online (Sandbox Code Playgroud)

slow_query_log_file通过检查上面打印的内容来检查慢速日志/usr/local/mysql/data/slow.log

您可以通过以下方式了解信息。

    # 时间:2019-04-26T01:48:19.890846Z
    # 用户@主机: root[root]@localhost[] Id:5124
    # Query_time: 0.000575 Lock_time: 0.000146 Rows_sent: 3 Rows_examined: 3
    设置时间戳=1556243299;
    Select * from mytable where ID=5 限制 3;
    # 时间:2019-04-26T01:48:34.672888Z
    # 用户@主机: root[root]@localhost[] Id:5124
    # Query_time: 0.000182 Lock_time: 0.000074 Rows_sent: 1 Rows_examined: 1
    设置时间戳=1556243314;
    Select * from mytable where ID=5 限制 1;

运行Rows_exmained时值等于limit参数值。测试在MySQL 5.7.18上完成。

----------------------------------另一种验证方式------------------------ ----------------------


    mysql> 显示类似“%Innodb_rows_read%”的状态;
    +------------------+------+
    | 变量名 | 价值|
    +------------------+------+
    | Innodb_rows_read | Innodb_rows_read | 13 |
    +------------------+------+
    一组 1 行(0.00 秒)

    mysql> Select * from mytable where ID=5 限制 1;
    +----------------+----+--------+----------+
    | 聚类_键| 身份证 | 数据| 位置 |
    +----------------+----+--------+----------+
    | 5 | 5 | 数据5 | 7 |
    +----------------+----+--------+----------+
    一组 1 行(0.00 秒)

    mysql> 显示类似“%Innodb_rows_read%”的状态;
    +------------------+------+
    | 变量名 | 价值|
    +------------------+------+
    | Innodb_rows_read | Innodb_rows_read | 14 | 14
    +------------------+------+
    一组 1 行(0.00 秒)

您可以看到Innodb_rows_read限制 1 只增加了 1。如果执行全表扫描查询,您可以看到该值将增加表的计数。

    mysql> 从 mytable 中选择 count(*);
    +----------+
    | 计数(*)|
    +----------+
    | 126296 | 126296
    +----------+
    1 行一组(0.05 秒)

    mysql> 显示类似“%Innodb_rows_read%”的状态;
    +------------------+--------+
    | 变量名 | 价值|
    +------------------+--------+
    | Innodb_rows_read | Innodb_rows_read | 505204 |
    +------------------+--------+
    一组 1 行(0.00 秒)

    mysql> 从 mytable 中选择 *,其中 Data=“Data-5”;
    +----------------+----+--------+----------+
    | 聚类_键| 身份证 | 数据| 位置 |
    +----------------+----+--------+----------+
    | 5 | 5 | 数据5 | 7 |
    | 26293 | 26293 5 | 数据5 | 26 | 26
    | 26301 | 26301 5 | 数据5 | 7 |
    +----------------+----+--------+----------+
    3 行一组(0.09 秒)

    mysql> 显示类似“%Innodb_rows_read%”的状态;
    +------------------+--------+
    | 变量名 | 价值|
    +------------------+--------+
    | Innodb_rows_read | Innodb_rows_read | 631500 | 631500
    +------------------+--------+
    一组 1 行(0.00 秒)

两种方式都证实了explainfor limit 似乎提供了有关所检查行的误导性信息。