在MySQL中使用不等于符号还能走索引吗?

一般情况下,我们会在一个索引上较多的使用等值查询或者范围查询,此时索引大多可以帮助我们极快的查询出我们需要的数据。

那当我们在where条件中对索引列使用!=查询,索引还能发挥他的作用吗?

以此SQL为例:

select * from t where k != 6; 

MySQL会如何执行这个SQL呢?是直接全表扫描吗?

其实,走不走索引,只取决于一个因素,那就是成本。

我们知道,MySQL中有一个叫做优化器的东西,他会对每一条查询sql做成本分析,然后根据分析结果选择是否使用索引或者全表扫描。

对于上面的sql,优化器会将k!=6转化为两个区间查询(-∞,6)和(6,+∞),然后对索引树进行成本计算。

我们画一个简略版的二级索引树。

简单解释一下:每个颜色代表一个数据页(MySQL与磁盘交互是以页为单位,默认一个页是16kb,这里我们假设一个页存两条数据,并且MySQL规定页中的数据会有序排放并组成一个单向链表)。

对于一个普通的二级索引,叶子节点存储是索引列和主键值,非叶子节点页存储是下方叶子节点的最小值和对应的页地址。(叶子节点是有序的,对应的主键可不一定)

那么对于两个区间查询(-∞,6)和(6,+∞)意味着什么呢?

如果一个二级索引树的数据简化为12条数据,那么就有1-5,7-12共计11条数据要被扫描,然后进行11次回表。

也就是说,如果表中有120万条数据,要回表110万次。

emm,MySQL一看这么麻烦,还扫描什么二级索引树啊,直接全表扫描走起吧。

那难道说,对于!=查询就用不了索引了吗?

非也。

如果数据集是下面这种,情况可能就不一样了。

在这个索引树上,索引值为6的占据了很大一部分,那么MySQL扫描成本就会大大降低了。

此时扫描的行数变成了1,10-12,共计3行。

相对于全表扫描,此时走二级索引树扫描,显然代价是比较低的。

也就是说,对于!=是否可以使用索引,要看具体的场景。

总结一下就是,MySQL判断某个sql是否走索引,其实取决于成本分析。

如果使用二级索引的成本更低,MySQL就会倾向于使用二级索引。

如果使用二级索引扫描的行数占比过高,导致需要频繁的回表,MySQL经过计算之后觉得走二级索引的代价太大了,就会使用全表扫描。

finally,都看到这里了,点个赞再走呗。

<think>好的,我现在需要回答用户关于如何在MySQL使用索引优化查询性能的问题。根据用户提供的引用内容,我需要整理出最佳实践,并且确保回答结构清晰,符合用户的要求。 首先,我需要回顾用户提供的引用内容,看看有哪些关键点可以提取。引用[1]提到选择合适的索引列,引用[2]提到使用EXPLAIN分析查询,引用[3]强调合理选择和设计索引的重要性,引用[4]指出使用索引可以优化临时表的创建,引用[5]则提到了21个最佳实践,包括设计表结构时的注意事项。 接下来,我需要将这些信息组织成逻辑连贯的步骤或建议。可能的结构是按重要性排序,或者分点列出同的最佳实践。比如,先讲选择合适的索引列,然后如何设计索引,接着使用工具分析,最后避免常见的错误。 另外,用户要求生成相关问题,我需要根据内容提出相关的问题,比如如何选择索引列、如何分析索引效果、索引的维护等。同时,必须注意使用中文回答,并正确应用LaTeX格式,比如在提到数学表达式时用$符号包裹。 需要注意的还有,引用标识要自然地添加到相关段落的末尾。比如,当提到选择合适的索引列时,添加[^1],提到使用EXPLAIN时添加[^2],等等。 现在,我需要检查是否有遗漏的关键点。例如,覆盖索引索引顺序、避免过多索引、字符串索引前缀这些点是否在引用中有提到。引用[5]提到设计表结构时的考虑,可能涉及到索引的顺序和选择性高的列。引用[4]提到使用索引来避免临时表,所以在优化排序和分组时可以应用这一点。 另外,注意使用Markdown格式,使用自然的中文段落,用列表形式分点说明。每个要点需要简明扼要,同时结合引用内容进行解释。 最后,生成的相关问题应该围绕索引的最佳实践,比如如何选择索引列、优化方法、维护策略、分析工具等。确保问题与回答内容紧密相关,帮助用户进一步深入了解。 总结步骤: 1. 整理引用中的关键点。 2. 分点列出最佳实践,每个点结合引用内容。 3. 添加引用标识到对应的位置。 4. 生成相关问题,覆盖回答中的各个部分。 5. 检查LaTeX格式是否正确,数学表达式是否正确使用$符号。 6. 确保语言流畅,结构清晰,符合用户要求。</think>### 如何在MySQL使用索引优化查询性能 以下是优化查询性能的**8个关键实践**,结合MySQL特性与实际案例分析: 1. **优先为高频查询条件与连接字段创建索引** 对`WHERE`、`JOIN`、`ORDER BY`子句中的列建立索引。例如,查询`SELECT * FROM orders WHERE user_id=100`时,应为`user_id`创建索引。 选择**区分度高**的列(如唯一值比例高的列),如身份证号比性别更适合建索引。 2. **使用复合索引时注意列顺序** 复合索引遵循**最左前缀原则**。例如索引$(a,b,c)$可支持`WHERE a=1`或`WHERE a=1 AND b=2`,但无法单独使用$b$或$c$。 将**高频查询条件**放在左侧,且范围查询列尽量靠后。例如$(status, create_time)$适合`WHERE status=1 AND create_time > '2023-01-01'`[^5]。 3. **利用覆盖索引减少IO** 若索引包含查询所需的所有列(如$(user_id, name)$),则无需回表查数据文件。例如: ```sql SELECT name FROM users WHERE user_id=100 -- 使用覆盖索引 ``` 4. **优化排序与分组操作** 对`ORDER BY`或`GROUP BY`的列建索引可避免文件排序。例如: ```sql CREATE INDEX idx_time ON logs(create_time); SELECT * FROM logs ORDER BY create_time DESC LIMIT 10 -- 避免Using filesort ``` 通过索引可减少临时表生成[^4]。 5. **使用EXPLAIN分析执行计划** 通过`EXPLAIN`查看是否命中索引、扫描行数等关键指标: ```sql EXPLAIN SELECT * FROM products WHERE category_id=5; ``` 关注`type`列(应出现`ref`或`range`)、`rows`列(扫描行数越少越好)[^2]。 6. **避免索引滥用** - **删除冗余索引**:如已存在$(a,b)$,则单独索引$a$通常冗余 - **限制索引数量**:每个表建议超过5-7个索引,避免写操作性能下降 - **谨慎使用长字符串索引**:用前缀索引优化,如`INDEX(email(20))` 7. **字符串索引优化技巧** ```sql -- 使用前缀索引(前20个字符) CREATE INDEX idx_name ON users(name(20)); -- 对哈希值建立索引(如存储URL) ALTER TABLE pages ADD url_hash CHAR(32), ADD INDEX(url_hash); ``` 8. **定期维护索引** 通过`OPTIMIZE TABLE`重建索引碎片: ```sql OPTIMIZE TABLE orders; -- 每月执行一次 ``` 使用`SHOW INDEX`检查索引基数: ```sql SHOW INDEX FROM users; -- 查看Cardinality值 ``` ### 案例分析 某订单表查询缓慢: ```sql SELECT * FROM orders WHERE status='shipped' AND create_time BETWEEN '2023-01-01' AND '2023-06-30' ORDER BY total_price DESC; ``` 优化步骤: 1. 创建复合索引$(status, create_time, total_price)$ (覆盖查询条件和排序) 2. 验证执行计划是否使用索引扫描 3. 添加`total_price`倒序索引以优化排序: ```sql CREATE INDEX idx_status_time_price ON orders(status, create_time, total_price DESC); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员拾山

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值