mysql 联合索引原理详述在一个市民信息表上,是否有必要将身份证号
和名字建立联合索引?
假设这个市民表的定义是这样的:
CREATE TABLE `tuser` (
`id` int(11) NOT NULL,
`id_card` varchar(32) DEFAULT NULL,
`name` varchar(32) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`ismale` tinyint(1) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `id_card` (`id_card`),
KEY `name_age` (`name`,`age`)
) ENGINE=InnoDB
我们知道,身份证号是市民的唯一标识 。也就是说,如果有根据身份证号查询市民信息的需求,
我们只要在身份证号字段上建立索引就够了 。而再建立一个(身份证号、姓名)的联合索引,是
不是浪费空间?
如果现在有一个高频请求,要根据市民的身份证号查询他的姓名,这个联合索引就有意义了 。它
可以在这个高频请求上用到覆盖索引,不再需要回表查整行记录,减少语句的执行时间 。
当然,索引字段的维护总是有代价的 。因此 , 在建立冗余索引来支持覆盖索引时就需要权衡考虑
了 。这正是业务 DBA , 或者称为业务数据架构师的工作 。
最左前缀原则
看到这里你一定有一个疑问,如果为每一种查询都设计一个索引,索引是不是太多了 。如果我现
在要按照市民的身份证号去查他的家庭地址呢?虽然这个查询需求在业务中出现的概率不高,但
总不能让它走全表扫描吧?反过来说,单独为一个不频繁的请求创建一个(身份证号 , 地址)的
索引又感觉有点浪费 。应该怎么做呢?
这里 , 我先和你说结论吧 。B树这种索引结构,可以利用索引的“最左前缀” , 来定位记录 。
为了直观地说明这个概念 , 我们用(name,age)这个联合索引来分析 。
图 2 (name,age)索引示意图
可以看到 , 索引项是按照索引定义里面出现的字段顺序排序的 。
当你的逻辑需求是查到所有名字是“张三”的人时,可以快速定位到 ID4,然后向后遍历得到所有
需要的结果 。
如果你要查的是所有名字第一个字是“张”的人,你的 SQL 语句的条件是"where name like ‘张
%’" 。这时 , 你也能够用上这个索引,查找到第一个符合条件的记录是 ID3,然后向后遍历,直
到不满足条件为止 。
可以看到 , 不只是索引的全部定义,只要满足最左前缀,就可以利用索引来加速检索 。这个最左
前缀可以是联合索引的最左 N 个字段,也可以是字符串索引的最左 M 个字符 。
基于上面对最左前缀索引的说明,我们来讨论一个问题:在建立联合索引的时候,如何安排索引
【mysql联合索引怎么走 mysql联合索引和单个索引】 内的字段顺序 。
这里我们的评估标准是,索引的复用能力 。因为可以支持最左前缀,所以当已经有了 (a,b) 这个
联合索引后,一般就不需要单独在 a 上建立索引了 。因此,第一原则是,如果通过调整顺序,可
以少维护一个索引,那么这个顺序往往就是需要优先考虑采用的 。
所以现在你知道了,这段开头的问题里,我们要为高频请求创建 (身份证号,姓名)这个联合索
引,并用这个索引支持“根据身份证号查询地址”的需求 。
那么,如果既有联合查询,又有基于 a、b 各自的查询呢?查询条件里面只有 b 的语句 , 是无法
使用 (a,b) 这个联合索引的 , 这时候你不得不维护另外一个索引,也就是说你需要同时维护
(a,b)、(b) 这两个索引 。
这时候,我们要考虑的原则就是空间了 。比如上面这个市民表的情况 , name 字段是比 age 字段
大的 ,那我就建议你创建一个(name,age) 的联合索引和一个 (age) 的单字段索引 。
MySQL中如何设置唯一索引,联合索引?1.UNIQUE 关键字建唯一索引\x0d\x0amysql CREATE TABLE `wb_blog` (\x0d\x0a-`id` smallint(8) unsigned NOT NULL,\x0d\x0a-`catid` smallint(5) unsigned NOT NULL DEFAULT '0',\x0d\x0a-`title` varchar(80) NOT NULL DEFAULT '',\x0d\x0a-`content` text NOT NULL,\x0d\x0a-PRIMARY KEY (`id`),\x0d\x0a-UNIQUE KEY `catename` (`catid`)\x0d\x0a- ) ;\x0d\x0a如果建好表了,可以用以下语句建\x0d\x0a mysql CREATE UNIQUE INDEX catename ON wb_blog(catid);\x0d\x0a\x0d\x0a2.联合索引\x0d\x0aALTER TABLE `tasks`\x0d\x0aADD INDEX `testabc` (`title`, `created`) ;\x0d\x0a\x0d\x0a3联合唯一索引(假设有这个需求,在同一天内不能建两个tiltle一样的任务)\x0d\x0aALTER TABLE `tasks`\x0d\x0aADD UNIQUE INDEX `testabc` (`title`, `created`) ;\x0d\x0a\x0d\x0a数据库建索引的科学性事关数据库性能,索引也不是越多越好 。
深入理解mysql的联合索引 最近在学习MySQL的存储引擎和索引的知识 。看了许多篇介绍MyISAM和InnoDB的索引的例子,都能理解 。
像这张索引图:
PS:该图来自大神张洋的《MySQL索引背后的数据结构及算法原理》一文 。
但许多文章讲述的都是单列索引,我很好奇 联合索引对应的结构图是怎样的 。
比方说联合索引 (col1, col2,col3),我知道在逻辑上是先按照col1进行排序再按照col2进行排序最后再按照col3进行排序 。因此如果是select * from table where col1 = 1 and col3 = 3的话,只有col1的索引部分能生效 。但是其物理结构上这个联合索引是怎样存在的 , 我想不懂 。
上网查阅了许多资料,总算有点眉目了 。
假设这是一个多列索引(col1, col2,col3),对于叶子节点,是这样的:
PS:该图改自《MySQL索引背后的数据结构及算法原理》一文的配图 。
也就是说,联合索引(col1, col2,col3)也是一棵B Tree,其非叶子节点存储的是第一个关键字的索引,而叶节点存储的则是三个关键字col1、col2、col3三个关键字的数据,且按照col1、col2、col3的顺序进行排序 。
配图可能不太让人满意,因为col1都是不同的,也就是说在col1就已经能确定结果了 。自己又画了一个图(有点丑),col1表示的是年龄,col2表示的是姓氏,col3表示的是名字 。如下图:
PS:对应地址指的是数据记录的地址 。
如图,联合索引(年龄, 姓氏,名字),叶节点上data域存储的是三个关键字的数据 。且是按照年龄、姓氏、名字的顺序排列的 。
因此,如果执行的是:
select * from STUDENT where 姓氏='李' and 名字='安';
或者
select * from STUDENT where 名字='安';
那么当执行查询的时候,是无法使用这个联合索引的 。因为联合索引中是先根据年龄进行排序的 。如果年龄没有先确定,直接对姓氏和名字进行查询的话,就相当于乱序查询一样,因此索引无法生效 。因此查询是全表查询 。
如果执行的是:
select * from STUDENT where 年龄=1 and 姓氏='李';
那么当执行查询的时候,索引是能生效的,从图中很直观的看出,age=1的是第一个叶子节点的前6条记录,在age=1的前提下,姓氏=’李’的是前3条 。因此最终查询出来的是这三条,从而能获取到对应记录的地址 。
如果执行的是:
select * from STUDENT where 年龄=1 and 姓氏='黄' and 名字='安';
那么索引也是生效的 。
而如果执行的是:
select * from STUDENT where 年龄=1 and 名字='安';
那么,索引年龄部分能生效,名字部分不能生效 。也就是说索引部分生效 。
因此我对联合索引结构的理解就是B Tree是按照第一个关键字进行索引,然后在叶子节点上按照第一个关键字、第二个关键字、第三个关键字…进行排序 。
而之所以会有最左原则,是因为联合索引的B Tree是按照第一个关键字进行索引排列的 。
联合索引在B 树上的结构介绍
mysql联合索引如何创建?CREATE TABLE `test` ('aaa' varchar(16) NOT NULL default '', 'bbb' varchar(16) NOT NULL default '','ccc' int(11) UNSIGNED NOT NULL default 0, KEY `sindex` (`aaa`,`bbb`,`ccc`) )ENGINE=MyISAM COMMENT='';\x0d\x0a\x0d\x0a这样就在 aaa、bbb、ccc 3列上建立联合索引了 。\x0d\x0a\x0d\x0a如果表已经建好了,那么就在phpmyadmin里面执行:\x0d\x0aalert table test add INDEX `sindex` (`aaa`,`bbb`,`ccc`) \x0d\x0a\x0d\x0a就可以在这3列上建立联合索引了 。
mysql联合索引字段顺序原始sql
他的执行计划
可见,这个sql执行过程是被命中索引了的,索引如下
这个索引创建的稍微有点问题,在查询筛选中 , 如果用到了范围查询,在创建联合索引的时候,应该尽量把需要范围查询的字段放在最后
在上面创建的索引中,首先命中 f_start_time 字段索引,由于他是当前联合索引的第一个字段 , 那么他就不会在去走索引的第二个字段了;
他的执行过程是先通过索引查询出符合时间范围的数据,由引擎返回给服务器,然后服务器再执行where条件筛选,故在extra中出现了 using where
为了解决这个问题,创建这个索引的过程应该是本着让索引命中更多列的原则,把startTime字段放在联合索引的最后,优化后的索引如下:
Mysql建立索引经验在实际开发中使用数据库时,难免会遇到一些大表数据 , 对这些数据进行查询时,有时候SQL会查询得特别慢,这时候,有经验mysql联合索引怎么走的老师傅会告诉mysql联合索引怎么走你,你看一下哪几个字段查的多,加一个索引就好了 。
那么,怎么合理地建立索引呢?这里分享一下我的一些经验,如有不妥之处,欢迎批评指正 。
1、不要盲目建立索引,先分析再创建
索引虽然能大幅度提升我们的查询性能,但也要知道,在你进行增删改时 , 索引树也要同样地进行维护 。所以,索引不是越多越好,而是按需建立 。最好是在一整块模块开发完成后,分析一下,去针对大多数的查询,建立联合索引 。
2、使用联合索引尽量覆盖多的条件
这是说在一个慢sql里假如有五个where , 一个 order by , 那么我们的联合索引尽量覆盖到这五个查询条件 , 如果有必要,order by 也覆盖上。
3、小基数字段不需要索引
这个意思是 , 如果一张表里某个字段的值只有那么几个 , 那么你针对这个字段建立的索引其实没什么意义,比如说,一个性别字段就两种结果,你建了索引,排序也没什么意思(也就是索引里把男女给分开了)
所以说,索引尽量选择基数大的数据去建立,能最大化地利用索引
4、长字符串可以使用前缀索引
我们建立索引的字段尽量选择字段类型较小的 , 比如一个varchar(20)和varchar(256)的,我们在20的上面建立的索引和在256上就有明显的差距(字符串那么长排序也不好排呀,唉) 。
当然,如果一定是要对varchar(256)建立索引,我们可以选择里面的前20个字符放在索引树里(这里的20不绝对,选择能尽量分辨数据的最小字符字段设计),类似这样KEY index(name(20),age,job),索引只会对name的前20个字符进行搜索 , 但前缀索引无法适用于order by 和 group by 。
5、对排序字段设计索引的优先级低
如果一个SQL里我们出现了范围查找 , 后边又跟着一个排序字段,那么我们优先给范围查找的字段设置索引,而不是优先排序 。
6、如果出现慢SQL,可以设计一个只针对该条SQL的联合索引 。
不过慢SQL的优化,需要一步步去进行分析,可以先用explain查看SQL语句的分析结果 , 再针对结果去做相应的改进 。explain的东西我们下次再讲 。
PS:在 select 语句之前增加 explain 关键字,MySQL 会在查询上设置一个标记,执行查询会返回执行计划的信息,而不是 执行这条SQL 。
mysql联合索引怎么走的介绍就聊到这里吧 , 感谢你花时间阅读本站内容 , 更多关于mysql联合索引和单个索引、mysql联合索引怎么走的信息别忘了在本站进行查找喔 。
推荐阅读
- 店铺如何写营销广告文案,店铺广告文案怎么写
- 苹果4怎么同步到手机相册,iphone4如何传照片
- 小班体育游戏林间穿梭,小班游戏林中穿梭
- 什么CPU能带动3060,什么CPU能带动4090
- vb.net求日期间隔 vb计算日期间隔
- sqlserver循环取字符,sqlserver 循环
- 软件连接服务器失败,软件连接服务器失败10060
- 怎么判断部首PPT,判断偏旁部首
- php数据库查询字符串 php 查找字符串