在工作中我们经常要与数据库打交道,数据优化已经成为一个无法避免的问题,在这里先不考虑 mysql 服务器优化、连接数、主从同步等问题,只优化数据,以及更好的业务处理。

PS:这里我们假设数据是百万级,超过百万级可能就有一些纸上谈兵了,因为我还没有在 mysql 上处理过千万级以上的数据。

数据类型

选择最合适的类型,来存储数据,当然这是废话,就只说几个点吧。

1、小数类型为 decimal,禁止使用 float 和 double。float 和 double 在存储的时候,存在精度损失的问题,很可能在值的比较时,得到不正确的结果。如果存储的数据范围超过 decimal 的范围,建议将数据拆成整数和小数分开存储。mysql 在保存值时进行四舍五入,因此在 float(7,4) 列内插入 9999.00009 的近似结果是 999.0001。

2、存储的字符串长度几乎相等,使用 char 定长字符串类型。如 md5 加密过的值,或者类似微信 openid 的值。

3、varchar 是可变长字符串,不预先分配存储空间,长度不要超过 5000,如果存储长 度大于此值,定义字段类型为 text,独立出来一张表,用主键来对应,避免影响其它字段索 引效率。

4、表必备三字段:id, gmt_create, gmt_modified。其中 id 必为主键,类型为 unsigned bigint、单表时自增、步长为 1,如果考虑到以后数据量会增大,可以使用 mysql 里面的 uuid_short() 函数来生成 id 以方便表数据拆分。gmt_create, gmt_modified 的类型均为 date_time 类型。

5、字段允许适当冗余,以提高性能,但是必须考虑数据同步的情况。冗余字段应遵循:

1)不是频繁修改的字段。

2)不是 varchar 超长字段,更不能是 text 字段。

6、单表行数超过 500 万行或者单表容量超过 2GB,才推荐进行分库分表。如果预计三年后的数据量根本达不到这个级别,请不要在创建表时就分库分表。

7、合适的字符存储长度,不但节约数据库表空间、节约索引存储,更重要的是提升检 索速度。 正例:无符号值可以避免误存负数,且扩大了表示范围。

对象

年龄区间

类型

表示范围

150 岁之内

unsigned tinyint

无符号值:0 到 255

数百岁

unsigned tinyint

无符号值:0 到 65535

恐龙化石

数千万年

unsigned tinyint

无符号值:0 到约 42.9 亿

太阳

约 50 亿年

unsigned tinyint

无符号值:0 到约 10 的 19 次方

8、使用 ENUM 而不是 VARCHAR 。ENUM 类型是非常快和紧凑的。在实际上,其保存的是 TINYINT,但其外表上显示为字符串。这样一来,用这个字段来做一些选项列表变得相当的完美。

索引规则与优化

mysql 索引分为 B+tree 与 Hash 两种常用的类型, 默认索引为 B+tree。

Hash 索引仅仅能满足"=","IN"和"<=>"查询,不能使用范围查询。

B+tree 最左前缀匹配特性,如果左边的值未确定,那么无法使用此索引(页面搜索严禁左模糊或者全模糊,如果需要请走搜索引擎来解决,之前我们用 sphinx,后迁移到 solr)。

1、业务上具有唯一特性的字段,即使是组合字段,也必须建成唯一索引。

PS: 不要以为唯一索引影响了 insert 速度,这个速度损耗可以忽略,但提高查找速度是明 显的;另外,即使在应用层做了非常完善的校验和控制,只要没有唯一索引,根据墨菲定律("凡是可能出错的事必定会出错"), 必然有脏数据产生。

2、超过三个表禁止 join。需要 join 的字段,数据类型保持绝对一致;多表关联查询 时,保证被关联的字段需要有索引。

3、在 varchar 字段上建立索引时,必须指定索引长度,没必要对全字段建立索引,根据 实际文本区分度决定索引长度。

PS: 索引的长度与区分度是一对矛盾体,一般对字符串类型数据,长度为 20 的索引,区分度会高达 90% 以上,可以使用 count(distinct left(列名, 索引长度)) / count(*) 的区分度 来确定。InnoDB 单列索引长度不能超过 767bytes,实际上联合索引还有一个限制是 3072bytes。

4、如果有 order by 的场景,请注意利用索引的有序性。order by 最后的字段是组合 索引的一部分,并且放在索引组合顺序的最后,避免出现 file_sort 的情况,影响查询性能。

5、建组合索引的时候,区分度最高的在最左边。

6、创建索引时避免有如下极端误解:

1)误认为一个查询就需要建一个索引。

2)误认为索引会消耗空间、严重拖慢更新和新增速度。

3)误认为唯一索引一律需要在应用层通过“先查后插”方式解决。

7、尽量避免 null:应该指定列为 not null,除非你想存储 null。在 mysql 中,含有空值的列很难进行查询优化,因为它们使得索引、索引的统计信息以及比较运算更加复杂。你应该用 0、一个特殊的值或者一个空串代替空值。

8、where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。where 子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。

sql 规则与优化

1、不要使用 count(列名)或 count(常量)来替代 count(*),count(*) 就是 SQL92 定义的标准统计行数的语法,跟数据库无关,跟 null 和非 null 无关。count(*)会统计值为 null 的行,而 count(列名) 不会统计此列为 null 值的行。

2、count(distinct col) 计算该列除 null 之外的不重复数量。注意 count(di col1, col2) 如果其中一列全为 null,那么即使另一列有不同的值,也返回为 0。

3、当某一列的值全是 null 时,count(col) 的返回结果为 0,但 sum(col) 的返回结果为 null,因此使用 sum() 时需注意 NPE 问题。可以使用如下方式来避免 sum 的 NPE 问题:select IF(ISnull(SUM(g)),0,SUM(g)) FROM table;

4、在代码中写分页查询逻辑时,若 count 为 0 应直接返回,避免执行后面的分页语句。

5、不得使用外键与级联,一切外键概念必须在应用层解决。(外键影响数据库的插入速度)

6、禁止使用存储过程,存储过程难以调试和扩展,更没有移植性。

7、in 操作能避免则避免,若实在避免不了,需要仔细评估 in 后边的集合元素数量,控 制在 1000 个之内。

8、如果有全球化需要,所有的字符存储与表示,均以 utf-8mb4 编码。

PS: 从 mysql5.5 开始,可支持 4 个字节 UTF 编码,只要将编码标记成 utf8mb4 即可。并且 utf8mb4 是兼容 utf8 ,并支持 emoji 表情。

9、查看慢查询 sql 日志,使用 explain 命令调试索引命中信息,先 sql 运行看看是否真的很慢,注意设置 SQL_NO_CACHE。

查询结果解释如下:

id:select 标识符,表示 select 的查询序列号

select_type:表示 select 语句的类型。可取值有:SIMPLE 表示简单的查询,不包括连接查询和子查询;PRIMARY 表示主查询,或者最外层的查询语句;UNION 表示连接查询的第 2 个或者后面的查询语句;DEPENDENT UNIO 连接查询中的第 2 个或后面的 select 语句,取决于外面的查询;UNION RESULT 连接查询的结果;SUBQUERY 子查询中的第 1 个 select 语句;DEPENDENT SUBQUERY 子查询中的第 1 个select ,取决于外面的查询;DERIVED 表示导出表的 select

table:表示查询的表

type:表示表的连接类型,如下是从最佳类型到最差类型的介绍。

1、system:该表是仅有一行的系统表,是 const 连接类型的一个特例

2、const:数据表最多只有一个匹配行,将在查询开始时被读取,并在余下的查询优化中作为常量对待。const 用于使用常数值比较 PRIMARY KEY 或 UNIQUE 索引的所有部分的场合

3、eq_ref:对于每个来自前面表的行组合,从该表中读取一行。当一个索引的所有部分都在查询中使用并且索引是 UNIQUE 或 PRIMARY KEY 时,即可使用该类型

4、ref:对于来自前面的表的任意行组合,将从该表中读取所有匹配行。这种类型用于索引既不是 UNIQUE 也不是 PRIMARY KEY 的情况,或者查询中使用了索引列的子集。ref 可以用于使用 = 或者 <=> 操作符的带索引的列

5、ref_or_null:该连接类型如同 ref,但是添加了 mysql 可以专门搜索包含 null 值得行。在解决子查询中常使用该连接类型的优化。

6、index_merge:该连接类型使用了索引合并优化方法

7、unique_subquery:一个索引查找函数,可以完全替换子查询,效率更高(见表2)

8、index_subquery:该连接类型类似于 unique_subquery,可以替换 IN 子查询

9、range:只检索给定范围的行,使用一个索引来选择行

10、index:该连接类型与ALL相同除了只扫描索引树。由于索引文件通常比数据文件小,因此 index 比 ALL 快

11、ALL:对于前面表的任意行组合,进行完整的表扫描,通常可以增加索引来避免使用ALL连接

possible_keys:表示 mysql 能使用哪个索引在该表中找到行,如果为 null 表示没有相关索引。在这种情况下,通过检查 where 子句看它是否引用某些列或适合索引的列来提高查询性能。如果有,则可通过创建索引提高查询性能

key:表示查询实际使用的索引,该值为 null 表示没有选择索引。

key_len:表示 mysql 选择的索引字段按子节计算的长度

ref:表示使用哪个列或常数与索引一起来查询记录

rows:显示 mysql 在表中查询时必须检查的行数

Extra:该列 mysql 在处理查询时的详细信息

10、可以使用连接(join)查询来代替子查询。连接查询不需要建立临时表,其速度比子查询更快,如果查询中使用索引的话,性能会更佳。连接之所以有更高的效率,是因为 mysql 不需要再内存中创建临时表来完成查询工作。

总结

上面的文章基本都是我从网上收集并整体修改的,大部分都是我工作中所遇到的问题,最后我抛出三个问题。

1、如何设计一张百万级的用户表结构。

2、百万级用户表后台分页。

3、通过昵称查询用户信息,昵称可以重复。

参考文献

2、施瓦茨 (Baron Schwartz) 等 著,宁海元等 译;高性能MySQL(第3版);2013年5月1日

3、姜承尧 著;数据库技术丛书·MySQL技术内幕:InnoDB存储引擎(第2版);2013年6月5日

4、姜承尧 著;MySQL技术内幕:SQL编程。

mysql unique_subquery_mysql 数据优化相关推荐

  1. MySQL百万数据优化总结 一

    测试的数据库配置 数据库配置阿里云RDS 存储类型 ESSD PL1 云盘 数据库内存 1024 M 数据库类型 MySQL8.0 CPU 1 核 MySQL8.0 中文参考手册:MySQL8.0中文 ...

  2. mysql大数据优化要注意的细节

    值得学习的东西,转载~ 1.对查询进行优化.应尽量避免全表扫描.首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中对字段进行 null 值判断. ...

  3. MySQL百万数据优化一

  4. mysql数据没有真正提交,转MySQL 批量提交优化

    用户修改布局时,需要批量更新mysql的xxxx_layout_xxxx表.批量操作的数据量是2-30条/次.批量操作是这次项目在技术上比较关键的一个点,之前批量操作做过性能上的测试,mysql端问题 ...

  5. mysql 大量数据 更改索引_Mysql索引数据结构详解与索引优化

    本篇文章主要学习了MySQL的索引的数据结构的认识,做一个大概的了解即可. 一.索引 在关系数据库中,索引是一种单独的.物理的对数据库表中一列或多列的值进行排序的一种存储数据结构,它是某个表中一列或若 ...

  6. MySQL大数据量分页查询方法及其优化

    点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:收藏了!7 个开源的 Spring Boot 前后端分离优质项目个人原创+1博客:点击前往,查看更多 链接:ht ...

  7. mysql的limit优化_mysql数据库limit优化例子(百万级数据)

    limit优化对于站长来说是经常会要用到了,同样的数据不同做法可以提升不少的性能了,下面我们来看一篇关于mysql数据库limit优化例子,具体如下. 今天看到一篇文章讲的就是mysql数据有100万 ...

  8. mysql 定时统计_PHP+MySQL定时数据统计优化

    这次给大家带来PHP+MySQL定时数据统计优化,PHP+MySQL定时数据统计优化的注意事项有哪些,下面就是实战案例,一起来看一下. 在互联网项目中,对项目的数据分析必不可少.通常会统计某一段时间内 ...

  9. 面试官问:在读多写少的情况下,如何优化 MySQL 的数据查询方案

    作者 | 面试官问     责编 | 张文 来源 | 面试官问(ID:interviewer_asked) 面试官问:假设你负责的某业务在双十一期间要搞运营活动,公司投入了大量的营销费用进行推广,此举 ...

最新文章

  1. mysql5.7 首次登陆_mysql5.7.20第一次登录失败的快速解决方法
  2. 电商网站模板_阿里云建站:模板建站与定制建站怎么选(小白参考)
  3. caffe模型文件解析_深度学习 Caffe 初始化流程理解(数据流建立)
  4. 软件开发人员薪资标准 人月_IT从业者培训前后薪资差距近3000块钱
  5. ORACLE之字符集修改(10g)
  6. 关于车辆和车牌的检测相关文章
  7. java tomcat jms_java – 使用ActiveMQ和Spring的JMS Standalone使用者
  8. 未能创建可接受的游标。
  9. SpringBoot常用注解之@Retryable
  10. 数据-第19课-递归的应用实战一
  11. 董明珠赞同取消住房公积金 格力员工每人一套房
  12. 鸿蒙大陆v2.8正式版,鸿蒙大陆正式版地图下载-鸿蒙大陆下载 V2.22--pc6下载站
  13. 三流大学和一流大学学生的简历有什么区别?
  14. KF UD分解之UD分解基础篇【1】
  15. springboot 调用方法事物_springboot中使用@Transactional注解事物不生效的坑
  16. 数据库32位升级到64位解决方案
  17. 【C++】相对路径与绝对路径以及斜杠与反斜杠的区别
  18. 用Random产生1到10之间的一个随机数
  19. java识别农作物病虫害源码,一种基于微信公众号的农作物虫害识别方法及其系统与流程...
  20. Android调用返回键

热门文章

  1. 我国农村人均收入增长将连续三年超GDP增长幅度
  2. 苹果手机如何清除微信记录?专业操作助你从此操作告别“假删除”!
  3. 计算机术语新年祝福,流行语:新年常用祝福用语
  4. 无法注册:DAO350.dll,THREED32.OCX的解决方案
  5. 【Akka】Akka入门编程实例
  6. 录像机可以使用笔记本电脑作为显示器吗?
  7. 云队友丨黄峥的理想国,拼多多的天花板
  8. Linux执行tar解压报错tar: Error is not recoverable: exiting now
  9. 豌豆夹Redis解决方案Codis源码剖析:Proxy代理
  10. mysql数据库入门 3 +每日一问