• 数据库索引


    索引

    创建并使用正确的索引【减少数据访问】

    优点:加快检索速度、唯一索引保证每条数据唯一性等等,对生产系统的性能有质的提升;

    缺点:索引会大大增加表记录的DML开销;

    拓展:索引对DML(INSERT,UPDATE,DELETE)附加的开销有多少?

    这个没有固定的比例,与每个表记录的大小及索引字段大小密切相关,以下是一个普通表测试数据,仅供参考:

    索引对于Insert性能降低56%

    索引对于Update性能降低47%

    索引对于Delete性能降低29%

    因此对于写IO压力比较大的系统,表的索引需要仔细评估必要性,另外索引也会占用一定的存储空间。

    正确的索引可以让性能提升100,1000倍以上,不合理的索引也可能会让性能下降100倍,因此在一个表中创建什么样的索引需要平衡各种业务需求。

    类别

    主键索引(聚集索引)、唯一索引、普通索引、组合索引、全文索引

    主键索引(聚集索引):primary key

    例子:

    ALTER TABLE `test_a` ADD INDEX `primary_key` (`id` ASC);

    唯一索引:unique index

    例子:

    create unique index name_season_unique on test_a(name, season);

    或者:

    ALTER TABLE `test_a` ADD UNIQUE INDEX `name_season_unique` (`name` ASC, `season` ASC);

    建议:尽量不用UNIQUE,由程序保证约束

    普通索引:index

    常用于

    • 搜索时经常使用到的字段
    • 用于连接其它表的字段
    • 用于外键字段
    • 高选中性的字段
    • order by子句中使用到的字段
    • xml类型

    不适用于:
    唯一性太差的字段不适合单独创建索引,即使频繁作为查询条件,例如性别
    更新非常频繁的字段不适合创建索引,例如登录次数,最后登录时间
    不会出现在 where 子句中的字段不该创建索引
    例子:

    create index name_index on test_a(name);

    或者:

    ALTER TABLE `test_a` ADD INDEX `name_index` (`name` ASC);

    组合索引(也叫复合索引、多列索引)

    类似于普通索引,只是索引是放在多个列名上,例如字典表中部首+笔画的组合索引

    create index name_no_index on test_a(name, season);

    全文索引:fulltext index

    create fulltext index name_fulltext_index on test_a(name);
    -- 创建用于展示效果的数据
    INSERT INTO `test_a` (`id`, `name`, `season`) VALUES ('6', '不知水果', '不知季度');
    -- 展示效果
    select match(name) against('不知水果') from test_a where id in(1, 6);
    drop index name_fulltext_index on test_a;

    0表示没有匹配到,或者你的词是停止词,是不会建立索引的.
    使用全文索引,不能使用like语句,如果使用like这样就不会使用到全文索引了

    在建表的时候建立唯一键、普通索引、唯一索引的方式如下:

    PRIMARY KEY (`id`),
    UNIQUE KEY `name_season_unique` (`name`,`season`),
    KEY `name_index` (`name`)

    拓展:
    删除索引

    DROP INDEX index_name ON table_name;

    或者:

    ALTER TABLE `table_name` DROP INDEX `index_name`;

    查看索引:

    show index from table_name;

    修改索引
    我们一般是先删除再重新创建,也可以直接进行修改

    索引注意点

    • 索引并不是越多越好,要根据查询有针对性的创建,考虑在WHERE和ORDER BY命令上涉及的列建立索引,可根据EXPLAIN来查看是否用了索引还是全表扫描
    • 应尽量避免在WHERE子句中对字段进行NULL值判断,否则将导致引擎放弃使用索引而进行全表扫描
    • 值分布很稀少的字段不适合建索引,例如”性别”这种只有两三个值的字段
    • 字符字段只建前缀索引
    • 字符字段最好不要做主键
    • 不用外键,由程序保证约束
    • 使用多列索引时主意顺序和查询条件保持一致,同时删除不必要的单列索引
    • 查询要建立索引最重要的条件是查询条件中需要使用索引
    • 如果MySQL估计使用全表扫描要比使用索引快,则不使用索引

    SQL什么条件会使用索引?

    当字段上建有索引时,通常以下情况会使用索引:

    • INDEX_COLUMN = ?
    • INDEX_COLUMN > ?
    • INDEX_COLUMN >= ?
    • INDEX_COLUMN < ?
    • INDEX_COLUMN <= ?
    • INDEX_COLUMN between ? and ?
    • INDEX_COLUMN in (?,?,...,?)
    • INDEX_COLUMN like ?||'%'(后导模糊查询)
    • T1. INDEX_COLUMN=T2. COLUMN1(两个表通过索引字段关联)

    SQL什么条件建了索引但不会使用索引?

    查询条件

    不能使用索引原因

    示例

    INDEX_COLUMN <> ?

    INDEX_COLUMN not in (?,?,...,?)

    不等于操作不能使用索引

     

    function(INDEX_COLUMN) = ?

    INDEX_COLUMN + 1 = ?

    INDEX_COLUMN || 'a' = ?

    经过普通运算或函数运算后的索引字段不能使用索引

     

    INDEX_COLUMN like '%'||?

    INDEX_COLUMN like '%'||?||'%'

    含前导模糊查询的Like语法不能使用索引

    对于使用like的查询,'aaa%' 会使用到索引,查询如果是'%aaa'不会使用到索引。 explain select * from dept where name like '研发部%'; -- 不会使用索引 explain select * from dept where name like '%研发部';

    INDEX_COLUMN is null

    B-TREE索引里不保存字段为NULL值记录,因此IS NULL不能使用索引

     

    NUMBER_INDEX_COLUMN='12345'

    CHAR_INDEX_COLUMN=12345

    在做数值比较时需要将两边的数据转换成同一种数据类型,如果两边数据类型不同时会对字段值隐式转换,相当于加了一层函数处理,所以不能使用索引。

    如果列类型是字符串,那一定要在条件中将数据使用引号引用起来。否则不使用索引。(添加时,字符串必须'') -- 会应用索引 explain select * from dept where name = '研发部'; -- 不会使用索引并且报错 explain select * from dept where name = 研发部;

    a.INDEX_COLUMN=a.COLUMN_1

    给索引查询的值应是已知数据,不能是未知字段值。

     

    对于创建的组合索引,只要查询条件使用了最左边的列,索引一般就会被使用,不是使用的第一部分,则不会使用索引

    组合索引都是从第一个字段开始找起,看第一个条件字段是否是组合索引的第一个字段,如果是则使用索引,否则不使用

    alter table dept add index name_loc (name, loc); explain select * from dept where name = '研发部'; explain select * from dept where name = '研发部' and loc = '大厦10楼1001'; -- 不会使用索引 explain select * from dept where loc = '大厦10楼1001';

    如果条件中有or,即使其中有条件带索引也不会使用。

     

    -- 我们把组合索引删除,然后只在name上加入索引 alter table dept drop index name_loc; alter table dept add index name_index (name); -- 使用了索引 explain select * from dept where name = '研发部'; -- key为NULL explain select * from dept where name = '研发部' or loc = '大厦10楼1001';

    注:

    经过函数运算的字段要使用索引可以使用函数索引,这种需求建议与DBA沟通。

    我们一般在什么字段上建索引?

    这是一个非常复杂的话题,需要对业务及数据充分分析后再能得出结果。主键及外键通常都要有索引,其它需要建索引的字段应满足以下条件:

    1、字段出现在查询条件中,并且查询条件可以使用索引;

    2、语句执行频率高,一天会有几千次以上;

    3、通过字段条件可筛选的记录集很小,那数据筛选比例是多少才适合?

    这个没有固定值,需要根据表数据量来评估,以下是经验公式,可用于快速评估:

    小表(记录数小于10000行的表):筛选比例<10%

    大表:(筛选返回记录数)<(表总记录数*单条记录长度)/10000/16

    单条记录长度≈字段平均内容长度之和+字段数*2

    例如:emp表中有600万的数据,单条记录长度 ≈ (7+6+6+3+8+4+1+10+7+6) + 11 * 2 = 70

    筛选返回记录数就需要小于 6000000 * 70 / 10000 / 16 = 3625 左右即可

    在emp的name字段中添加了索引,查看索引筛选比例如下,351小于预期值3625,说明在这个字段上建立索引是非常合理的

    image

    如何知道SQL是否使用了正确的索引?

    简单SQL可以根据索引使用语法规则判断,复杂的SQL不好办,判断SQL的响应时间是一种策略,但是这会受到数据量、主机负载及缓存等因素的影响,有时数据全在缓存里,可能全表访问的时间比索引访问时间还少。要准确知道索引是否正确使用,需要到数据库中查看SQL真实的执行计划。

    只通过索引访问数据

    有些时候,我们只是访问表中的几个字段,并且字段内容较少,我们可以为这几个字段单独建立一个组合索引,这样就可以直接只通过访问索引就能得到数据,一般索引占用的磁盘空间比表小很多,所以这种方式可以大大减少磁盘IO开销。

    如:select id,name from company where type='2';

    如果这个SQL经常使用,我们可以在type,id,name上创建组合索引

    create index my_comb_index on company(type,id,name);

    有了这个组合索引后,SQL就可以直接通过my_comb_index索引返回数据,不需要访问company表。

    切记,性能优化是无止境的,当性能可以满足需求时即可,不要过度优化。在实际数据库中我们不可能把每个SQL请求的字段都建在索引里,所以这种只通过索引访问数据的方法一般只用于核心应用,也就是那种对核心表访问量最高且查询字段数据量很少的查询。

    优化SQL执行计划

    SQL执行计划是关系型数据库最核心的技术之一,它表示SQL执行时的数据访问算法。由于业务需求越来越复杂,表数据量也越来越大,程序员越来越懒惰,SQL也需要支持非常复杂的业务逻辑,但SQL的性能还需要提高,因此,优秀的关系型数据库除了需要支持复杂的SQL语法及更多函数外,还需要有一套优秀的算法库来提高SQL性能。

    目前ORACLE有SQL执行计划的算法约300种,而且一直在增加,所以SQL执行计划是一个非常复杂的课题,一个普通DBA能掌握50种就很不错了,就算是资深DBA也不可能把每个执行计划的算法描述清楚。虽然有这么多种算法,但并不表示我们无法优化执行计划,因为我们常用的SQL执行计划算法也就十几个,如果一个程序员能把这十几个算法搞清楚,那就掌握了80%的SQL执行计划调优知识。

    查看索引的使用情况

    show status like 'Handler_read%';

    大家可以注意:
    handler_read_key:这个值越高越好,越高表示使用索引查询到的次数。
    handler_read_rnd_next:这个值越高,说明查询低效。

    这时我们会看到handler_read_rnd_next值很高,这是因为我们前面没有加索引的时候,做过多次查询的原因.

    定时清除不需要的数据,定时整理索引锁片

    当创建了索引并且索引正常的工作,但性能仍然不好,那就可能是产生了索引碎片,需要进行索引碎片处理。
    optimize table table_name;

  • 相关阅读:
    git stash 一个场景 mark
    sendBeacon 使用
    【踩坑笔记】layui之单选和复选框不显示
    wordpress后台管理超时没反应:load-scripts.php载入缓慢出错
    MySQL_Sql_打怪升级_进阶篇_测试: SQL随机生成测试数据
    MySQL_Sql_打怪升级_进阶篇_测试: 游标应用
    MySQL8.0新特性_01_JSON数据格式的支持
    MySQL_Sql_打怪升级_进阶篇_进阶19: 函数
    MySQL_Sql_打怪升级_进阶篇_进阶18: 存储过程
    MySQL_Sql_打怪升级_进阶篇_进阶17: 变量
  • 原文地址:https://www.cnblogs.com/tufujie/p/9650224.html
Copyright © 2020-2023  润新知