关于mysql:SQL-性能优化梳理

49次阅读

共计 4035 个字符,预计需要花费 11 分钟才能阅读完成。

前言

本文次要针对的是关系型数据数据库 MySql。键值类数据库能够参考:

https://www.jianshu.com/p/098a870d83e4

先简略梳理下 Mysql 的基本概念,而后分创立时和查问时这两个阶段的优化开展。

1 基本概念简述

1.1 逻辑架构

  • 第一层:客户端通过连贯服务,将要执行的 sql 指令传输过去
  • 第二层:服务器解析并优化 sql,生成最终的执行打算并执行
  • 第三层:存储引擎,负责数据的贮存和提取

1.2 锁

数据库通过锁机制来解决并发场景 - 共享锁(读锁)和排他锁(写锁)。读锁是不阻塞的,多个客户端能够在同一时刻读取同一个资源。写锁是排他的,并且会阻塞其余的读锁和写锁。简略提下乐观锁和乐观锁。

  • 乐观锁,通常用于数据竞争不强烈的场景,多读少写,通过版本号和工夫戳实现。
  • 乐观锁,通常用于数据竞争强烈的场景,每次操作都会锁定数据。

要锁定数据须要肯定的锁策略来配合。

  • 表锁,锁定整张表,开销最小,然而会加剧锁竞争。
  • 行锁,锁定行级别,开销最大,然而能够最大水平的反对并发。

然而 MySql 的存储引擎的实在实现不是简略的行级锁,个别都是实现了多版本并发管制(MVCC)。MVCC 是行级锁的变种,少数状况下防止了加锁操作,开销更低。MVCC 是通过保留数据的某个工夫点快照实现的。

1.3 事务

事务保障一组原子性的操作,要么全副胜利,要么全副失败。一旦失败,回滚之前的所有操作。MySql 采纳主动提交,如果不是显式的开启一个事务,则每个查问都作为一个事务。

隔离级别管制了一个事务中的批改,哪些在事务内和事务间是可见的。四种常见的隔离级别:

  • 未提交读(Read UnCommitted),事务中的批改,即便没提交对其余事务也是可见的。事务可能读取未提交的数据,造成脏读。
  • 提交读(Read Committed),一个事务开始时,只能看见已提交的事务所做的批改。事务未提交之前,所做的批改对其余事务是不可见的。也叫不可反复读,同一个事务屡次读取同样记录可能不同。
  • 可反复读(RepeatTable Read),同一个事务中屡次读取同样的记录后果时后果雷同。
  • 可串行化(Serializable),最高隔离级别,强制事务串行执行。

1.4 存储引擎

InnoDB 引擎,最重要,应用最宽泛的存储引擎。被用来设计解决大量短期事务,具备高性能和主动解体复原的个性。
MyISAM 引擎,不反对事务和行级锁,解体后无奈平安复原。

2 创立时优化

2.1 Schema 和数据类型优化

整数

TinyInt,SmallInt,MediumInt,Int,BigInt 应用的存储 8,16,24,32,64 位存储空间。应用 Unsigned 示意不容许正数,能够使负数的上线进步一倍。

实数

  • Float,Double , 反对近似的浮点运算。
  • Decimal,用于存储准确的小数。

字符串

  • VarChar,存储变长的字符串。须要 1 或 2 个额定的字节记录字符串的长度。
  • Char,定长,适宜存储固定长度的字符串,如 MD5 值。
  • Blob,Text 为了存储很大的数据而设计的。别离采纳二进制和字符的形式。

工夫类型

  • DateTime,保留大范畴的值,占 8 个字节。
  • TimeStamp,举荐,与 UNIX 工夫戳雷同,占 4 个字节。

优化倡议点

  • 尽量应用对应的数据类型。比方,不要用字符串类型保留工夫,用整型保留 IP。
  • 抉择更小的数据类型。能用 TinyInt 不必 Int。
  • 标识列(identifier column),倡议应用整型,不举荐字符串类型,占用更多空间,而且计算速度比整型慢。
  • 不举荐 ORM 零碎主动生成的 Schema,通常具备不重视数据类型,应用很大的 VarChar 类型,索引利用不合理等问题。
  • 实在场景混用范式和反范式。冗余高查问效率高,插入更新效率低;冗余低插入更新效率高,查问效率低。
  • 创立齐全的独立的汇总表 \ 缓存表,定时生成数据,用于用户耗时工夫长的操作。对于精确度要求高的汇总操作,能够采纳 历史后果 + 最新记录的后果 来达到疾速查问的目标。
  • 数据迁徙,表降级的过程中能够应用影子表的形式,通过批改原表的表名,达到保留历史数据,同时不影响新表应用的目标。

2.2 索引

索引蕴含一个或多个列的值。MySql 只能高效的利用索引的最左前缀列。索引的劣势:

  • 缩小查问扫描的数据量
  • 防止排序和零时表
  • 将随机 IO 变为程序 IO(程序 IO 的效率高于随机 IO)

B-Tree

应用最多的索引类型。采纳 B -Tree 数据结构来存储数据(每个叶子节点都蕴含指向下一个叶子节点的指针,从而不便叶子节点的遍历)。B-Tree 索引实用于全键值,键值范畴,键前缀查找,反对排序。

B-Tree 索引限度:

  • 如果不是依照索引的最左列开始查问,则无奈应用索引。
  • 不能跳过索引中的列。如果应用第一列和第三列索引,则只能应用第一列索引。
  • 如果查问中有个范畴查问,则其左边的所有列都无奈应用索引优化查问。

哈希索引

只有准确匹配索引的所有列,查问才无效。存储引擎会对所有的索引列计算一个哈希码,哈希索引将所有的哈希码存储在索引中,并保留指向每个数据行的指针。

哈希索引限度:

  • 无奈用于排序
  • 不反对局部匹配
  • 只反对等值查问如 =,IN(),不反对 < >

优化倡议点

  • 留神每种索引的适用范围和实用限度。
  • 索引的列如果是表达式的一部分或者是函数的参数,则生效。
  • 针对特地长的字符串,能够应用前缀索引,依据索引的选择性抉择适合的前缀长度。
  • 应用多列索引的时候,能够通过 AND 和 OR 语法连贯。
  • 反复索引没必要,如(A,B)和(A)反复。
  • 索引在 where 条件查问和 group by 语法查问的时候特地无效。
  • 将范畴查问放在条件查问的最初,避免范畴查问导致的左边索引生效的问题。
  • 索引最好不要抉择过长的字符串,而且索引列也不宜为 null。

3 查问时优化

3.1 查问品质的三个重要指标

  • 响应工夫(服务工夫,排队工夫)
  • 扫描的行
  • 返回的行

3.2 查问优化点

  • 防止查问无关的列,如应用 Select * 返回所有的列。
  • 防止查问无关的行
  • 切分查问。将一个对服务器压力较大的工作,合成到一个较长的工夫中,并分屡次执行。如要删除一万条数据,能够分 10 次执行,每次执行实现后暂停一段时间,再继续执行。过程中能够开释服务器资源给其余工作。
  • 合成关联查问。将多表关联查问的一次查问,分解成对单表的屡次查问。能够缩小锁竞争,查问自身的查问效率也比拟高。因为 MySql 的连贯和断开都是轻量级的操作,不会因为查问拆分为屡次,造成效率问题。
  • 留神 count 的操作只能统计不为 null 的列,所以统计总的行数应用 count(*)。
  • group by 依照标识列分组效率高,分组后果不宜出行分组列之外的列。
  • 关联查问提早关联,能够依据查问条件先放大各自要查问的范畴,再关联。
  • Limit 分页优化。能够依据索引笼罩扫描,再依据索引列关联本身查问其余列。如

    SELECT
     id,
     NAME,
     age
    WHERE
     student s1
    INNER JOIN (
     SELECT
       id
     FROM
       student
     ORDER BY
       age
     LIMIT 50,5
    ) AS s2 ON s1.id = s2.id
  • Union 查问默认去重,如果不是业务必须,倡议应用效率更高的 Union All

补充内容

来自大神 - 小宝

1. 条件中的字段类型和表构造类型不统一,mysql 会主动加转换函数,导致索引作为函数中的参数生效。

2.like 查问后面局部未输出,以 % 结尾无奈命中索引。

3. 补充 2 个 5.7 版本的新个性:
generated column,就是数据库中这一列由其余列计算而得

CREATE TABLE triangle (sidea DOUBLE, sideb DOUBLE, area DOUBLE AS (sidea * sideb / 2));
insert into triangle(sidea, sideb) values(3, 4);
select * from triangle;
+-------+-------+------+
| sidea | sideb | area |
+-------+-------+------+
|   3      |   4      |  6     |
+-------+-------+------+

反对 JSON 格局数据,并提供相干内置函数

CREATE TABLE json_test (name JSON);
INSERT INTO json_test VALUES('{"name1":"value1","name2":"value2"}');
SELECT * FROM json_test WHERE JSON_CONTAINS(name, '$.name1');

来自 JVM 专家 - 达

关注 explain 在性能剖析中的应用

EXPLAIN SELECT settleId FROM Settle WHERE settleId = "3679"

  • select_type,有几种值:simple(示意简略的 select,没有 union 和子查问),primary(有子查问,最里面的 select 查问就是 primary),union(union 中的第二个或随后的 select 查问,不依赖内部查问后果),dependent union(union 中的第二个或随后的 select 查问,依赖内部查问后果)
  • type,有几种值:system(表仅有一行(= 零碎表),这是 const 连贯类型的一个特例),const(常量查问), ref(非惟一索引拜访,只有一般索引),eq_ref(应用惟一索引或组件查问),all(全表查问),index(依据索引查问全表),range(范畴查问)
  • possible_keys: 表中可能帮忙查问的索引
  • key,抉择应用的索引
  • key_len,应用的索引长度
  • rows,扫描的行数,越大越不好
  • extra,有几种值:Only index(信息从索引中检索出,比扫描表快),where used(应用 where 限度),Using filesort(可能在内存或磁盘排序),Using temporary(对查问后果排序时应用长期表)

逆锋起笔 是一个专一于程序员的编程圈子,以分享 javaPython 学习资源 为主,关注即可支付 23 种精选的编程视频教程和大佬们举荐的电子版学习材料!

正文完
 0