MySQL SELECT中LIMIT时EXPLAIN估算ROWS不准确的替代方法

在MySQL性能调试中,常常使用EXPLAIN解释MySQL执行计划,从而用来估算性能耗时。其中,rows用来表示在SQL执行过程中会被扫描的行数,该数值越大,意味着需要扫描的行数,相应的耗时更长。但是需要注意的是EXPLAIN中输出的rows只是一个估算值,不能完全对其百分之百相信,如EXPLAIN中对LIMITS的支持就比较有限。可以参考文章《MySQL EXPLAIN limits and errors》


1. 创建一个测试用表TEMP作为实现

CREATE TABLE TEMP (

        TYPE varchar(64) NOT NULL,

        CREATED_AT timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)

);


2. 创建相应Index

CREATE INDEX IDX_TEMP_type_createdAt on TEMP(TYPE, CREATED_AT);


3. 随机插入数据

随机插入10000条数据,其中TYPE字段随机插入['A', 'B', 'C', 'D', 'E']五个值中的任意一个


4. 使用EXPLAIN进行rows解释

EXPLAIN SELECT * FROM TEMP WHERE TYPE = 'A' ORDER BY CREATED_AT DESC LIMIT 10;


结果:

select_type typekey key_len ref rowsfiltered Extra
SIMPLE ref IDX_TEMP_type_createdAt258 const2017 100Using where; Using index

可以看到rows是2017,有2017行被扫描


5. 使用SHOW STATUS尝试解释

a)首先执行SQL,注意去掉EXPLAIN

SELECT * FROM TEMP WHERE TYPE = 'A' ORDER BY CREATED_AT DESC LIMIT 10;


b)执行SHOW STATUS查看当前状态
SHOW SESSION STATUS LIKE "Handler%"

结果:
Variable_nameValue
Handler_commit 1
Handler_delete 0
Handler_discover 0
Handler_external_lock 2
Handler_mrr_init 0
Handler_prepare 0
Handler_read_first 1
Handler_read_key 2
Handler_read_last 0
Handler_read_next 0
Handler_read_prev9
Handler_read_rnd 0
Handler_read_rnd_next 3
Handler_rollback 0
Handler_savepoint 0
Handler_savepoint_rollback 0
Handler_update 0
Handler_write 0

可以看到还剩9条数据没有读,这才是实际准确的值




<think>嗯,用户想了解如何优化MySQL查询性能,特别是查询执行优化技巧和最佳实践。我需要结合现有的引用资料来组织回答。首先,得确定用户可能的需求层次,他们可能是开发人员或者数据库管理员,需要具体的优化方法,而仅仅是理论。 首先,根据引用[4]提到的索引优化,应该详细说明如何有效使用索引,包括创建索引的示例。比如避免在WHERE子句中使用函数,或者如何选择合适的索引类型。这部分需要具体例子,比如CREATE INDEX语句。 然后,引用[2]提到避免使用SELECT *,应该解释为什么选择具体字段更好,可能涉及减少数据传输和I/O开销。同,结合覆盖索引的概念,如果索引包含所有查询字段,可能需要回表,提高效率。 接下来是查询结构优化,比如避免复杂的子查询,改用JOIN,这可能需要解释执行计划的差异。还有分页优化,使用WHERE加范围查询而LIMIT OFFSET,特别是大数据量的延迟问题。 执行计划分析部分,引用[2]和引用[4]都提到了EXPLAIN的重要性,需要说明如何解读EXPLAIN的结果,比如type字段的值,rows估计等。这部分可能需要具体的关键指标,比如ALL表示全表扫描,需要避免。 数据库设计优化方面,规范化与反平衡的权衡,引用[4]提到的分表分库策略,可能需要举例说明何垂直分表,何水平分表。比如用户表和订单表分开,或者按间分片。 配置参数调整方面,连接池大小和缓存设置,比如query_cache_size和innodb_buffer_pool_size的设置建议。这部分需要给出调整的指导原则,而仅仅是参数名称。 另外,用户可能还关心实际案例,比如引用[2]中的案例1,避免SELECT *,可以具体说明性能提升的幅度。同,定期维护,如索引重建和表优化,也是重要的点。 最后,用户可能希望知道如何持续优化,比如监控工具的使用,定期分析慢查询日志。引用[3]提到的21个最佳实践,可以提示用户进一步参考,但可能无法直接引用内容,所以需要结合已有的引用资料。 需要注意回答的结构要清晰,分点说明,每个技巧都有原理和示例。同,生成的相关问题要围绕用户可能进一步想知道的内容,比如索引失效的情况、EXPLAIN的具体用法、分库分表策略等。确保引用标记正确,比如引用[1]、[2]等的位置要自然,比如在覆盖索引部分引用[4],在避免SELECT *引用[2]。</think>### MySQL查询性能优化技巧与最佳实践分步解析 #### 一、索引优化(核心优化手段) 1. **精准索引匹配原则** 在$WHERE$子句和$JOIN$条件涉及的列建立索引,例如用户表按$user_id$过滤: ```sql CREATE INDEX idx_user_id ON users(user_id); ``` 避免对索引列进行函数运算: ```sql -- 错误示例(索引失效) SELECT * FROM orders WHERE YEAR(order_date) = 2023 -- 优化方案 SELECT * FROM orders WHERE order_date BETWEEN '2023-01-01' AND '2023-12-31'[^4] 2. **覆盖索引技巧** 当索引包含查询所需所有字段,可避免回表操作。例如查询用户姓名: ```sql CREATE INDEX idx_user_info ON users(user_id, name); SELECT name FROM users WHERE user_id = 1001 ``` #### 二、查询结构优化 3. **字段选择优化** 避免使用$SELECT \*$,明确指定所需字段。当表有200列,查询$SELECT \*$会比指定5个字段多消耗40倍I/O资源[^2] 4. **子查询重构** 将相关子查询改为$JOIN$操作: ```sql -- 优化前 SELECT * FROM products WHERE category_id IN (SELECT id FROM categories WHERE type=1) -- 优化后 SELECT p.* FROM products p JOIN categories c ON p.category_id = c.id WHERE c.type = 1[^4] ``` 5. **分页优化** 大数据量分页使用游标方式: ```sql -- 传统分页(性能差) SELECT * FROM logs ORDER BY id LIMIT 1000000, 20 -- 优化分页 SELECT * FROM logs WHERE id > 1000000 ORDER BY id LIMIT 20 ``` #### 三、执行计划分析 6. **EXPLAIN工具使用** 通过执行计划分析关键指标: ```sql EXPLAIN SELECT * FROM orders WHERE total_amount > 1000; ``` 重点关注: - type列:应避免ALL(全表扫描),争取达到ref/range级别 - rows列:估算扫描行数 - Extra列:Using filesort/Using temporary需要警惕 #### 四、数据库设计优化 7. **数据分片策略** | 分片类型 | 适用场景 | 示例 | |---------|---------|------| | 垂直分片 | 列数超过200的表 | 用户基础信息与扩展信息分离 | | 水平分片 | 数据量超千万级 | 按间分片订单表 | #### 五、配置参数调优 8. **关键参数设置** ```ini innodb_buffer_pool_size = 系统内存的70%-80% query_cache_size = 128M # 适用于读多写少场景 max_connections = 500 # 根据实际连接需求调整[^3] ``` #### 六、定期维护策略 9. **碎片整理周期** ```sql OPTIMIZE TABLE high_write_table; -- 每月执行 ANALYZE TABLE user_profile; -- 每周统计信息更新[^4] ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值