MySQL索引二

序言

在上一篇文章中主要讲了索引的底层实现。主要讨论了为什么加了索引以后,数据库的查询效率会加快?底层怎么实现的?这个问题。
那么本文主要想讨论下以下几个问题

  1. 怎么建立合适索引,建立索引有哪些需要规避的要点?
  2. 为什么有时候建立了索引也没啥子用?
    以下是自己最近学习和使用的一些想法,希望大家可以互相交流,反正是技术交流哈哈。

首先抛出两个语句干货。大家可以先去自己的数据库执行检查下。

-- 查询冗余索引,看看是否有累赘索引

SELECT * from sys.schema_redundant_indexes;

-- 查询从未被使用到的索引,用都没用过的,留着做啥。

SELECT * from sys.schema_unused_indexes;

怎么建立合适索引,建立索引有哪些需要规避的要点

    首先我们要知道,索引并不是越多越好。虽然索引用的很爽。
    因为底层是B+树结构,我们在增,删,改操作中都会对B+树结构进行调整。
    所以索引过多也会影响此类操作。主要考虑在where和order by 后面涉及的列建立索引。
    同时,由于一条mysql在执行的时候,如果有多个索引命中,最终只能选择其中一个索引。

所以个人见解:

要点一:复合索引和单列索引相比,应优先使用复合索引。

    针对建立复合索引之前,需要先做一个调研把哪个字段作为最左前缀。
    调研可以从这几个方面去判断
    1.有哪个字段是经常会使用到的,且大部分sql中都会有值。
    举个例子:
    user表里有id,name,age,address,sex等字段。
    调研发现多数sql中都使用到了name这个字段作为查询条件。因此可建立复合索引idx_name_age_address(name,age,address)
    此处使用到的是mysql里最常见的最左原则。为什么会有这个原则,和底层原理有关,在上一篇文章中也叙述了。
    2.字段长度小的列放在左侧。因为字段长度小,每一页能存储的数据量就越大,IO性能越好,也就是越快找到目标数据。
    3.如果创建的复合索引中某个字段中的值都是不同的,那么他的数据区分度就高,走索引效率就非常明显,考虑放在左侧。
    这种复合索引比建立单列索引实用的多。

要点二:值比较稀少的列不建议使用索引

    比如上面例子中的sex字段。换句话说,建了索引也对查询效率起不了作用。那么为啥会有这种论断。
    因为系统在执行一条sql的时候,会进行预测走这个索引和全表扫描哪个扫描的行数少。扫描行数越少,I/O操作次数越少。
    而我们走索引的时候,会通过sex这个索引先查到主键索引,再通过主键索引来查找数据。也就是会走两次索引。也就是回表。
    系统通过索引的区分度来判断,索引上不同的值越多,这个基数越大,那么走索引查询越有优势。
    
    如果我们业务需要强制走某个索引查询的话。可以使用select * from user force idx(age) where address = '中国'

要点三:尽量建立覆盖索引

    所谓覆盖索引就是此索引覆盖所有需要查询的字段的值。尤其是查询频繁的语句,优先考虑覆盖索引。上述例子中
    建立了复合索引idx_name_age_address(name,age,address)
    查询语句:select id,name from user where name = '张三' and age = '20' and address = '中国'
    因为B+树的叶子节点存储的是主键+列值,最终还是要回表,就会比较慢。但覆盖索引要查询出的列和索引是对应的,不需要做回表操作。
    我们往往会因为偷懒或者想让sql能够复用,而使用select * from 的写法。但这种无法使用覆盖索引,也会消耗更多的CPU和IO

判断建立的索引是否有效

要点一:判断是否符合了最左前缀原则。

以上述例子中为例:
    建立了复合索引idx_name_age_address(name,age,address)
    查询语句:select * from user where  age = '20' and address = '中国'  
    此语句因为最左前缀为name,但是name没有作为条件查询,无法使用索引。

要点二:查看where 子句左边是否有进行函数,算术运算或者其他表达式运算

    select * from user where  age+1 = 20  -- 不能使用索引
    select * from user where  age = 20 -1 -- 能使用索引

要点三:尽量避免在WHERE子句中使用!=或<>操作符,将打算加索引的列设置为 NOT NULL。否则将导致引擎放弃使用索引而进行全表扫描。

要点四:查询语句有多个索引,数据库选错索引。

数据库使用采样的方式来预测各个索引的基数。既然是采样,就有可能失误。
若系统判断当前索引基数过小,就不走索引,直接全表扫描。
所以不要对每个单列建立索引。索引需要的是有效,而不是多。

要点五:联合索引的第一个索引使用了范围查找导致失效

以上述例子中为例:
     建立了复合索引idx_name_age_address(name,age,address)
    查询语句:select * from user where  name in ('张三',‘小敏’) and age = '20' and address = '中国'  
    在此sql中,name字段会用到索引,但是后面的age和address索引失效。
    因为一个 SQL 只能利用复合索引中的一列进行范围查询。
    所以如果有范围查询的字段可以放在复合索引的右边。不要使用not in 
    not in 通常会让索引失效,可以用left join 或者 not exist 替代。

要点六:排查是否使用了子查询

尽量不使用子查询,可用join替代。
因为子查询的结果集会存储在临时表中,而临时表是没有索引的。同时也会消耗过多的CPU和IO。也是慢sql的一部分原因。

总结

    其实mysql使用B+树作为自己的数据结构,它是非常强大的。千万数据量的大表,如果索引能够使用的合适,也完全能够支撑。
索引的重要性不言而喻,甚至在做开发设计评审时,索引也应该作为数据库设计里重要的一项进行评审。
如果文中有说的不正确的地方,希望大家能够互相交流,一起进步。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,470评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,393评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,577评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,176评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,189评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,155评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,041评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,903评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,319评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,539评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,703评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,417评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,013评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,664评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,818评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,711评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,601评论 2 353

推荐阅读更多精彩内容

  • 在满足语句需求的情况下, 尽量少地访问资源是数据库设计的重要原则之一。我们在使用数据库的时候,尤其是在设计表结构时...
    leafzl阅读 358评论 0 3
  • 设置索引 在执行CREATE TABLE语句时可以创建索引,也可以单独用CREATE INDEX或ALTER TA...
    IT的咸鱼阅读 190评论 0 0
  • 前言 要知道为什么使用索引,要知道如何去使用好索引,使自己的查询达到最优性能,需要先了解索引的数据结构和磁盘的存取...
    Java资讯库阅读 1,725评论 0 14
  • 1.A simple master-to-slave replication is currently being...
    Kevin关大大阅读 5,966评论 0 3
  • 索引 数据库中的查询操作非常普遍,索引就是提升查找速度的一种手段 索引的类型 从数据结构角度分 1.B+索引:传统...
    一凡呀阅读 2,914评论 0 8