【MySQL】9.索引&单表查询优化

0. 什么是索引?

在数据之外,数据库系统维护着一种帮助快速获取数据的有序的数据结构,这种数据结构实现了高级查找算法,以某种方式指向数据。索引会影响查找和排序的效率。

一般来说索引本身也很大,在不能全部存在内存中的情况下,会以索引键的形式存储在磁盘上。

一、优劣

1. 优势

  1. 对数据进行索引
    提高查找效率,降低数据库 IO 成本。
  2. 对数据进行排序
    降低排序成本和 CPU 消耗。

2. 劣势

  1. 索引实际上也是存于表中,记录索引的字段并指向实体的记录,同样占用空间;
  2. 对数据进行更新(增删改),每次更新索引字段等信息也需要更新,造成额外负担;
  3. 索引不是一劳永逸,而是要不断的调整。

3. 适合使用索引的场景

  1. 主键和唯一约束都会默认创建唯一索引;
  2. 频繁查询的字段适合使用索引;
  3. 连表查询的关联字段,外键关心建立索引;
  4. 排序字段可用索引降低消耗;
  5. 统计或分组字段适合索引。

4. 不适合索引的场景

  1. 频繁更新数据的字段不适合使用索引;
  2. 没用用于查找和排序的字段不适合索引;
  3. 记录太少,没必要建索引
  4. 重复值过多的字段不适合索引,如性别,即使建了索引也没有实际效果

二、索引分类

  1. 单值索引
    即一个索引对应一个列
  2. 复合索引
    一个索引对应多个列
  3. 唯一索引
    索引列须是唯一

三、语法

  1. 创建索引
create index [unique] indexName on tableName(columnName(length))
#或
alter table tableName add [unique] index 【indexName】(columnName)
#indexName 索引名
#tableName 表名
#columnName 列名
#length 列的长度
  1. 删除索引
drop index [indexName] on table
  1. 查看索引
show index from tableName

四、主要索引结构

  1. B-Tree 索引
  2. Hash 索引
  3. Full-text 索引
  4. R-Tree 索引

五、索引分析

索引失效不仅会使查询、排序变慢,还会使行锁变表锁,所以一定要避免索引失效

1. where后使用索引的原则

  1. 最好能到到全值匹配
    意思就是查询能够完全匹配索引,包括列和顺序,比如:
    创建了 idx_a_b_c,那么最好查询的时候也能按照 a,b,c 的进行查找。

  2. 最佳左前缀法则
    查询要从索引的最左侧开始,并且中间不能断,比如:
    创建了 idx_a_b_c,那么按照 a 查询,或者按照 a、b 查询,都是满足最佳最前缀法则的;
    而按照 b、c 或者 a、c 或者 c 查询都违反了此原则;
    a、c 还好,至少还有 a 可以使用索引,b、c 和 c 则索引完全用不上。

  3. 不要在索引列上做以下操作:计算,使用函数,类型转换(自动或手动)
    这类操作会导致索引失效,转向全表扫描

  4. 字符串不加单引号会导致索引失效
    例如,varchar 类型的字段 a,where a=1 和 where a='1'查询结果一样,但是 a=1 会导致 mysql 隐式的类型转换,导致索引失效
    用单引号,不要在用双引号了

  5. 范围条件搜索右侧都会失效
    例如,创建 idx_a_b_c,
    select * from t1 where a=1 and b>1 and c=1,这条语句中,a=1 是 ref 类型的,b>1是 range 类型的,这两个都用到了索引,但是 c=1 就无法使用索引了,因为 b>1 被打断了。此时,b 用到了索引,但是是用来排序,所以是 range 级别
    in 也是范围查找。

  6. 不等于(!= 或 <>)会导致索引失效,从而全表扫描

  7. is not null 会导致索引失效
    尽量索引字段有 null,可以增加空的默认值,例如''。

  8. like '%...' 或导致索引失效
    '%....' 会导致索引失效(索引类型变成 all,全表扫描),但 '....%' 仍是 range 类型索引(虽然是 range,但是这种比较特殊,和 >,< 不同,它不会打断索引,也就是说,他后边的索引还可以用)。

  9. 尽量使用覆盖索引,减少使用 select *
    例如 idx_a_b_c,select a,b,c 就可以形成覆盖索引(最好按顺序,可以少,但不可多于a,b,c),select * 则不行。

解决方法:利用覆盖索引,例如:select id from t1 where a like '%123%'(id 是主键,有唯一索引),这个查询类型是 index,优于 all。

  1. or 会导致索引失效,应少用
    解决办法:拆成多个语句,将查询结果合并即可。

  2. 创建复合索引的时候,尽量吧过滤性好的字段放在前边,例如:手机号姓名部门,这样每一个字段的筛选会过滤掉更多,使得后面的查询更轻松

具体是全部失效还是失效一般需验证----------------------------------------

2. order by

order by 使用索引的原则与 where 之后大部分相同,排序分为 using filesorts(文件内排序)和 using index(索引排序),对它的优化主要目标就是消除 using filesorts,使用 using index。

  1. 最佳左前缀原则
  2. 没有过滤条件的 order by,是用不到索引的,会产生 using filesort。也就是要有 where 过滤条件,或者加 limit。
  3. 多个字段排序顺序不同(同时存在asc,desc),也会产生 filesort
    其中,最左前缀原则举例:
    创建了索引 idx_a_b_c,
order b,c #不满足最前缀原则
where a='1' order by b,c #a是常量,不需排序,所以这个满足左前缀原则
where a like 'a%' order by b,c #同上
order c,a,b #不满足最前缀原则
order a asc,b desc #不能使用索引,必须同升同降
order by 与索引

但有时 using filesort 是不可避免的,而 filesort 又分为双路排序(mysql 4.1之前)和单路排序:

双路排序:要扫描两次磁盘得到最终数据,先读取(第一次)行指针和 order by 列到 buffer,并进行排序,按照排序后的虚拟列表重新从实体表中获取(第二次)数据,需要两次 IO,所以诞生了单路排序

单路排序:扫描一次得到数据,直接把所有查找列都读取出来,并在 buffer 中排序,然后将 buffer 中排序好的结果输出,只需要一次 IO

从上面可以看出,通常情况下,单路排序是要由于双路排序的,但仍存在特殊情况:取出数据太大,buffer 中存不下,单路排序只能每次取出 buffer 的大小的数据(创建 tmp 文件,多路合并),如此多次操作,完成全部数据的查找,导致多次 IO,效果可能比双路排序更糟。。。

解决办法就是调整 my.cnf 配置文件中一下两个参数:

sort_buffer_size,
max_length_for_sort_data

另外,需要什么字段就取,不要用 select *,避免查询结果因多余字段而过大,超过buffer 大小就不好了。

3. group by

group by 适用于分组,实际上是先排序,然后才分组。所以上面的 order by 的原则同样适用于 group by。如果 group by 使用不当,不仅会产生 using filesort,还会有 using temporary。

除了上面的几点,能用 where 就不要用 having。

select * 的危害

1. 影响覆盖索引
例如:有一个索引 idx_a_b_c, select a,b,c 或者 select a,b 都可以形成覆盖索引,因为查询字段小于等于索引的字段才能形成,一旦多于索引字段,就会无效。select * 却很有可能是查询字段多于索引字段
2. 排序生成临时表
由于 mysql 4.1 之后使用的都是单路排序(一次查询所有查询列到 buffer 中排序),由于 buffer 有限,一旦数据超出 buffer,就需要将数据分批存储到新创建的多个临时表中,全部查询、排序完成要进行整合,最后删除临时表。这一过程极其耗时,select * 增加了 buffer 爆满的风险。

msyql 优化器

mysql优化器,可以在查询时对sql进行优化,达到更好的查询效果,例如 idx_a_b_c, where 中的顺序是 a, c, b,这样 sql 优化器会对其进行优化成 a,b,c使索引得到应用。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 222,183评论 6 516
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,850评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,766评论 0 361
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,854评论 1 299
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,871评论 6 398
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,457评论 1 311
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,999评论 3 422
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,914评论 0 277
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,465评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,543评论 3 342
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,675评论 1 353
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,354评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,029评论 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,514评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,616评论 1 274
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 49,091评论 3 378
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,685评论 2 360

推荐阅读更多精彩内容