我在项目中对 MySQL 作的优化

原标题:我在 MySQL 上作了哪些优化
原文连接:zhoupq.com/我在-MySQL-上作…
转载请注明出处mysql

  本文记录了我这一年的时间里是如何对项目中用到的 MySQL 进行优化。带有必定的主观性和局限性,请各位支持的同时,不吝赐教。
算法

  

安装


  这是同事分享给个人。安装数据库也是一门学问,千万不要被安装的简单性而忽略一些细节。针对于 Win os 服务器而言,MySQL 的安装版能够选则三种不一样的服务器类型:

  • Developer Machine(开发机器)
      为 MySQL 分配最少分系统资源
  • Server Machine(服务器)
      为 MySQL 分配必定比例的系统资源
  • Dedicated MySQL Server Machine(专用MySQL服务器)
      为 MySQL 分配全部的系统资源

  若是你跟我同样不幸,不只选择了 Win os 作服务器系统,还选择了 Developer Machine(开发机器),兄弟抱一个,不要哭,重装。发生这些上述不幸的缘由已经不重要,须要作的是必须切换成 Dedicated MySQL Server Machine(专用MySQL服务器)sql

  重装切换以后,你会发现,以前安装的必定是假的 MySQL。数据库

主键


  主键或者惟一键能够用做某条记录的惟一标志符。主键生成有两种方式:
+ 自增
+ UUID

自增


  自增方式有个重要因素是“步长”,也就是则增的幅度,在单机模式下,通常步长为1。如果在分布式数据库系统下,步长设为节点的数量,这样一来,就能够避免主键重复的状况。建议预估好节点的数量,步长不可小于节点数。

UUID


  UUID 能够更有效地避免自增主键带来的烦恼,可是它也有不足之处:
+ UUID 过长,增大数据库总容量,下降性能
+ UUID 无序,插入数据时根据主键寻址费时

  针对上述 UUID 的缺点,推特开发了“雪花算法”,并开源。其中心思想是利用时间戳、数据中心码、机器码、序列号组成有规则的 UUID,使其有序下降性能消耗。

  我在项目中使用了“自增+步长2”,由于使用了主从,虽然不是分布式,可是双数据源也是两个节点,采用这种方式保险一些。

  更多内容请移步个人其余博文: 数据库自增加主键与-UUID
  推荐 MySQL 使用自增ID主键和UUID 做为主键的优劣比较详细过程(从百万到千万表记录测试)

数据类型

长度


  我一直秉承杀鸡就用杀鸡刀,宰牛采用宰牛刀的原则。一个“tab_NAME” 的数据类型非要整一个 “VARCHAR(500)”,这是浪费,过多的长度分配会形成空间占用太多,最终形成性能降低。有同事说我杞人忧天,一个库才二十几张表,即便每一个字段都设成500,也不过如此嘛。从短时间的结果上来看,结果没有受到明显影响。可是别忘了,咱们是来解决问题的,若是由于咱们的操做违反了约定,形成严重后果,那么咱们将背负罪过。“量身定作”的好处不言而喻,列的长度亦是如此。

NULL


  尽可能不将列设为 NULL,从业务角度上看,NULL 是错误的,试想,既然是 NULL,哪有何须存在这个列呢?反之,既然存在这个列,那么 NULL 便失去了意义。让我设计表的时候,我都会给列设置一个初始值,“tab_UPDATETIME” 就设置为 “CURRENT_TIMESTAMP”,“tab_STATUS” 就设置为 “1”或者“0”。

  从开发维护的角度看,若是不肯定列是否为 NULL,那么在 SQL 中,就必须加上 “AND tab_NAME != NULL AND tab_NAME != ''”,很容易被忽略,代码越多,出错的几率就越大。缓存

索引


  好的索引是一颗仙丹,可让迟缓的查询获得质的提高,不然,就是一碗毒药。

  索引我作了三点优化:bash

  • 勿滥用索引
  • 最左前缀索引
  • 前缀索引

勿滥用索引


  索引不是越多越好,由于生成索引须要时间,并且索引占表物理空间。表一大,查询速度多少会受影响。我亲眼看到同事建好表时候,无微不至地为每个字段都建了索引,或者为每个条件都建了索引,形如条件“a=1 and b =2 and c=3 and d=4”,为其建了“a”、“b”、“c”、“d”四个索引。浪费!低效!这种状况,应当使用“最左前缀索引”。

最左前缀索引


  在生成联合索引时会碰到最左前缀索引,什么是最左前缀索引呢?就是在联合索引中,从最左边的索引开始匹配,直到赶上“like”、“>”、“>=”、“<”、“<=”等范围匹配时中止,即便后面有“=”都再也不匹配。

  简单举例:现有字段“a”、“b”、“c”、“d”组成的联合索引“abcd”,SQL 条件部分为:服务器

  1. a=1 and b =2 and c=3 and d=4
  2. a=1 and b =2 and d=4 and c=3
  3. a=1 and b =2 and c>=3 and d=4

  1 用到索引为“abcd”,2 用到的索引为“abd”, (2 同 1)3 用到的索引为“abc”。条件的顺序很重要。跟自拍同样,脸大的站后面。
  
  抱歉,上述第二点同第一点,一样用到的索引为“abcd”。
  
  利用 EXPLAIN 工具分析:app

// 建表语句略,已知建立了组合索引 (abcd) 
mysql> EXPLAIN SELECT * FROM test t WHERE t.a = 'q' AND t.b = 'w' AND t.c = 'e' AND t.d = 'f';
+----+-------------+-------+------+---------------+------+---------+-------------------------+------+--------------------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref                     | rows | Extra                    |
+----+-------------+-------+------+---------------+------+---------+-------------------------+------+--------------------------+
|  1 | SIMPLE      | t     | ref  | name          | name | 360     | const,const,const,const |    1 | Using where; Using index |
+----+-------------+-------+------+---------------+------+---------+-------------------------+------+--------------------------+
1 row in set

mysql> EXPLAIN SELECT * FROM test t WHERE t.a = 'q' AND t.b = 'w' AND t.d = 'f' AND t.c = 'e';
+----+-------------+-------+------+---------------+------+---------+-------------------------+------+--------------------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref                     | rows | Extra                    |
+----+-------------+-------+------+---------------+------+---------+-------------------------+------+--------------------------+
|  1 | SIMPLE      | t     | ref  | name          | name | 360     | const,const,const,const |    1 | Using where; Using index |
+----+-------------+-------+------+---------------+------+---------+-------------------------+------+--------------------------+
1 row in set复制代码

前缀索引


  前缀索引是针对某个字段而言,咱们知道 MySQL 中,有一个全文索引,“BOLD”、“TEXT” 是不能建全文索引。想一想也能理解,这么长的全文索引得占多少空间,这显然是不现实的。最好的办法是为其建立“左前缀索引”,只取字符串的前面一小段做为索引,具体取多少,决定于多长的字符能够尽量多的肯定惟一记录。“varchar”一样受用。

  更多内容请移步个人其余博文:MySQL 高性能索引以前缀索引框架

多表联合查询


  不论是 Heibernate 在代码中拼 SQL,仍是 MyBatis 在 Mapper.xml 中写 SQL,因为数据库范式的规范,致使为完成某项查询,必须联合多表查询。一个 LEFT JOIN 很常见,三四个 LEFT JOIN 呢?

  多个 LEFT JOIN 确定不行,即便有索引,也很容易形成全表扫描,为了减小该状况发生的几率,我通常会采起两种方法:分布式

  • 反范式
  • 临时表

反范式

衡量一个 DBA 的水平有多高,得看他反范式能力有多强。
—— 知乎

  好比我要根据 A表 的日期,关联 B表,统计出每一个日期下某个属性的数量。我能够在A表中添加一列,用来存储“数量”,虽然违反了范式,可是性能上获得了提高。我以为这是一笔划算的买卖。

  规范化是为了技术服务,而技术是为业务服务。规范化也就是套路,能保证不出错,可是并不能解决特殊问题,特殊问题还须要特殊处理。

临时表


  当须要联合三张表以上时,轻微的反范式已经不适用了,推荐用临时表,或者物化视图,可是 MySQL 的物化视图实现起来比较困难。事实上,我用的就是临时表,将四张表的部分数据抽离出来,保存在一张临时表中,制定一个“计划”,天天凌晨会自动更新。

  • 好处
      加快查询速度
  • 缺点
    • 会在某一时刻(凌晨)数据库IO太高
    • 可能会出现异常,作好事务管理,让其回滚,从新执行,再有问题,就须要人工干预
    • 数据准确性会延迟一天,适合非敏感业务

  以上是仅针对数据库作的优化,至于缓存(一级缓存、二级缓存),那属于持久层框架的职责,不在此文记录范围以内。

相关文章
相关标签/搜索