前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >最佳多列索引公式

最佳多列索引公式

作者头像
用户6256742
发布2024-06-22 15:15:22
740
发布2024-06-22 15:15:22
举报
文章被收录于专栏:网络日志网络日志

x 个等值条件字段 + 1 个范围条件字段 or y 个排序字段 + z 个其他需要获取的字段。(x >= 0, y >= 0, z >= 0)

例子:

代码语言:javascript
复制
SELECT a, b, c, d, e FROM table WHERE a = 1 AND b = 2 ORDER BY c DESC, d ASC;

最佳索引为:

代码语言:javascript
复制
(   a,  b,     c DESC, d ASC,         e        )
  等值条件字段 |   排序条件字段   | 其他需要获取的字段

等值条件字段

等值条件字段是指 WHERE 中使用 = 的字段。比如 WHERE class = 2 中的 class 就是等值条件字段。

范围条件字段

范围条件字段是指 WHERE 中使用 ><>=<= 等操作符的字段。比如 WHERE score > 90 中的 score 就是范围条件字段。

范围条件对于查询效率的影响非常大,所以应该尽量减少范围条件的使用。在最佳多列索引公式中,最多有一个范围条件字段,且不能和排序字段并存。如果有排序需求,应优先考虑排序,想办法规避范围条件筛选。下面通过一个例子来说明为什么范围条件字段不能和排序字段并存,以及如何规避范围条件筛选。

假设有一个表 films,包含了电影的信息,其中包含了 namerelease_dateratingcountry 等字段。现在要查询评分大于 8.0 的中国电影并按上映日期排序,SQL 语句如下:

代码语言:javascript
复制
SELECT * FROM films WHERE rating > 8.0 AND country = 'China' ORDER BY release_date DESC;

当索引为 (country, rating, release_date) 时:

代码语言:javascript
复制
index on (country, rating, release_date)

                                                          |
                                                          v ------------->
+--------------++---------+---------+---------+-------+-------+-------+-------+-------+-------+-------+
| country      || America | America | America | China | China | China | China | Japan | Japan | Japan |
+--------------++---------+---------+---------+-------+-------+-------+-------+-------+-------+-------+
| rating       ||   6.0   |   8.5   |   9.0   |  7.0  |  8.5  |  9.0  |  9.5  |  8.0  |  8.5  |  9.0  |
+--------------++---------+---------+---------+-------+-------+-------+-------+-------+-------+-------+
| release_date ||  2024   |  2021   |  2023   | 2023  | 2015  | 2022  | 2016  | 2023  | 2013  | 2015  |
+--------------++---------+---------+---------+-------+-------+-------+-------+-------+-------+-------+
                                                         ✅       ✅      ✅

看起来这个索引很完美,但实际上通过索引查找到的结果并不是按照 release_date 排序的,也就是说索引中的 release_date 是无效的。数据库还需要将所有符合条件的行按照 release_date 进行排序,如果数据量很大,这个排序操作会非常耗时。如果我们仅仅需要前几条数据,那么这个排序操作就是浪费的。这就是为什么范围条件字段不能和排序字段并存,且应优先考虑排序的原因。

这种场景的优化方法是将范围条件转换为等值条件。这需要根据实际需求来做优化。比如我们例子中的需求是查询评分大于 8.0 的电影,我们可以将评分大于 8.0 的电影定义为高分电影。增加一个字段 is_high_rating,当评分大于 8.0 时,is_high_rating 为 1,否则为 0。然后将索引改为 (country, is_high_rating, release_date)

代码语言:javascript
复制
SELECT * FROM films WHERE is_high_rating = 1 AND country = 'China' ORDER BY release_date DESC;
代码语言:javascript
复制
index on (country, is_high_rating, release_date)

                                                                            |
                                                            <-------------- v
+----------------++---------+---------+---------+-------+-------+-------+-------+-------+-------+-------+
| country        || America | America | America | China | China | China | China | Japan | Japan | Japan |
+----------------++---------+---------+---------+-------+-------+-------+-------+-------+-------+-------+
| is_high_rating ||    0    |    1    |    1    |   0   |   1   |   1   |   1   |   1   |   1   |   1   |
+----------------++---------+---------+---------+-------+-------+-------+-------+-------+-------+-------+
| release_date   ||  2024   |  2021   |  2023   | 2023  | 2015  | 2016  | 2022  | 2013  | 2015  | 2023  |
+----------------++---------+---------+---------+-------+-------+-------+-------+-------+-------+-------+
                                                           ✅       ✅      ✅

如果数据库支持,也可以使用函数索引 (country, IF(rating > 8, 1, 0), release_date),或者使用虚拟列来实现。

注意: !=<>IS NOT NULL 等不等操作符也是范围条件。如有需要,也可以通过转换为等值条件来优化。

排序字段

排序字段是指 ORDER BY 中的字段。比如 ORDER BY release_date DESC 中的 release_date 就是排序字段。

排序字段的顺序应该和 ORDER BY 中的顺序一致,且升降序也应该一致或完全相反。例如 ORDER BY release_date DESC, rating ASC 对应的索引应该是 (release_date DESC, rating ASC)(release_date ASC, rating DESC)。之所以完全相反是因为数据库可以倒序遍历索引。例如我们要将查询按照 release_date 升序、rating 降序排序的前五个结果:

代码语言:javascript
复制
SELECT * FROM films ORDER BY release_date DESC, rating ASC LIMIT 5;

当索引为 (release_date DESC, rating ASC) 时:

代码语言:javascript
复制
index on (release_date DESC, rating ASC)

                     |
                     v -------------------------------->
+--------------++---------+-------+-------+---------+-------+---------+-------+-------+-------+-------+
| release_date ||  2024   | 2023  | 2023  |  2023   | 2022  |  2021   | 2016  | 2015  | 2015  | 2013  |
+--------------++---------+-------+-------+---------+-------+---------+-------+-------+-------+-------+
| rating       ||   6.0   |  7.0  |  8.0  |   9.0   |  9.0  |   8.5   |  9.5  |  8.5  |  9.0  |  8.5  |
+--------------++---------+-------+-------+---------+-------+---------+-------+-------+-------+-------+
                     ✅       ✅      ✅       ✅        ✅

当索引为 (release_date ASC, rating DESC) 时:

代码语言:javascript
复制
index on (release_date ASC, rating DESC)

                                                                                                  |
                                                                 <------------------------------- v
+--------------++---------+-------+-------+---------+-------+---------+-------+-------+-------+-------+
| release_date ||  2013   | 2015  | 2015  |  2016   | 2021  |  2022   | 2023  | 2023  | 2023  | 2024  |
+--------------++---------+-------+-------+---------+-------+---------+-------+-------+-------+-------+
| rating       ||   8.5   |  9.0  |  8.5  |   9.5   |  8.5  |   9.0   |  9.0  |  8.0  |  7.0  |  6.0  |
+--------------++---------+-------+-------+---------+-------+---------+-------+-------+-------+-------+
                                                                ✅        ✅      ✅      ✅       ✅

但是不能使用 (release_date DESC, rating DESC) 索引,因为这并不符合需求中的排序。

代码语言:javascript
复制
index on (release_date DESC, rating DESC)

                     |
                     v -------------------------------->
+--------------++---------+-------+-------+---------+-------+---------+-------+-------+-------+-------+
| release_date ||  2024   | 2023  | 2023  |  2023   | 2022  |  2021   | 2016  | 2015  | 2015  | 2013  |
+--------------++---------+-------+-------+---------+-------+---------+-------+-------+-------+-------+
| rating       ||   6.0   |  9.0  |  8.0  |   7.0   |  9.0  |   8.5   |  9.5  |  9.0  |  8.5  |  8.5  |
+--------------++---------+-------+-------+---------+-------+---------+-------+-------+-------+-------+
                     ✅       ✅      ✅       ✅        ✅

可以看出数据库使用 (release_date DESC, rating DESC) 索引获得的结果并不符合 ORDER BY release_date DESC, rating ASC 的排序要求,还需要进行额外的排序操作。

其他需要获取的字段(索引覆盖)

其他需要获取的字段指的是需要被 SELECT 且还不在索引中的字段。如果索引中包含了所有需要获取的字段,那么数据库可以直接从索引中获取数据,而不需要再去表中查询数据。这样可以减少 I/O 操作,提高查询效率。但是如果索引中包含了太多字段,会导致索引变得过大,从而影响到插入、更新、删除等操作的性能,也会增加不必要的内存占用。所以并不是直接把所有字段都放到索引中就是最佳的,需要根据实际情况来做权衡。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-06-11 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 等值条件字段
  • 范围条件字段
  • 排序字段
  • 其他需要获取的字段(索引覆盖)
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档