zoukankan      html  css  js  c++  java
  • Mysql分库、分表可能带来的问题与单库性能优化

    参考:https://www.cnblogs.com/lfs2640666960/p/11116962.html

    https://blog.csdn.net/cai13070139328/article/details/100099110

    数据的读写分离只是解决了访问的压力,但是存储的压力没有解决。

    要想解决存储的压力就要引入分库分表。

    分库:

      分库就是现在你有一个数据库服务器,数据库中有两张表分别是用户表和订单表。如果要分库的话现在需要两台机器,每个机器上安装一台数据库,一台机器上的数据库放用户表,一台机器上的数据库放订单表。这样存储压力就分担到两个服务器上了。

    分库带来的问题:

      联表查询问题,也就是join,之前在一个数据库里面可以用上join,用一条SQL语句就可以联表查询得到想要的结果,现在分为多个数据库join用不上了。比如要查注册时间在2019年之后用户的订单信息,你就需要先去数据库A中用户表查询注册在2019年之后的信息,然后得到用户id,再拿这些id去数据库B订单表中查询订单信息,然后再拼接这些信息返回,所以总体多写了一些代码。

      事务问题,现在不同的数据库事务就不是以前那个简单的本地事务了,而是分布式事务了,而引入分布式事务也提高了系统的复杂性,并且有些效率不高还会影响性能,例如Mysql XA,或者基于消息中间件实现的分布式事务。

    分表:

      如果一张表里面的数据量过大,会严重影响性能,这时候就要考虑分表。

      垂直分表:将列进行拆分,将那些不常用的列分到一张表,常用的分到一张表,这样每张表大小就会变小。垂直分表适合表中存在大量不常用的表。

           垂直分表的影响就是之前只要一个查询的,现在需要两次查询才能拿到分表之前的用户表信息。

      水平分表:水平分表适合行数很多的表,例如超过了5000万,有些场景可能超过1000万就要分表了。

           水平分表带来了路由问题,也就是按照什么原则分,可以按id范围、id hash等,或者搞一张表单独存放路由关系,不过,每次查询都得查两次如       果路由表太大,那么路由表又会成为瓶颈。

           带来的查询问题:比如要查询注册时间最早的前100名用户,这就等于你得在水平分的每一张表都order by一下注册时间,并且取100个,然后再       把每个表的100个结果对比一下得到最终结果。 整个操作变的复杂了,以前只需要1个order by操作,现在是多个order by。如果分了20个表,那       么20个order  by可能很耗时,串行执行则更慢。

    分库分表的实现:

      可以在客户端代码里面做,也可以使用中间件,这样客户端无感知。分库分表中间件可以使用Mycat。

      参考:https://blog.csdn.net/wt077521/article/details/80469015

         https://blog.csdn.net/weixin_38319645/article/details/81537849

    分库分表分区  怎么选:

      

    集群扩容:

      

    表的设计:

      表字段避免null值出现,null值很难查询优化且占用额外的索引空间,推荐默认数字0代替null。

      尽量使用INT而非BIGINT,如果非负则加上UNSIGNED,当然能使用TINYINT、SMALLINT、MEDIUM_INT更好。

      使用枚举或者整数代替字符串类型

      尽量使用TIMESTAMP而非DATATIME

      单表不要有太多字段,建议在20以内

      用整形来存IP

    索引:

      索引并不是越多越好,要根据查询有针对性的创建,考虑在WHERE和ORDER BY命令上涉及的列建立索引,可根据EXPLAIN来查看是否用了索引还是全表扫描

      应尽量避免在WHERE子句中对字段进行NULL值判断,否则将导致引擎放弃使用索引而进行全表扫描

      值分布很稀少的字段不适合建立索引,例如:性别

      字符字段只建前缀索引

      字符字段最好不要做主键

      不用外键,由程序保证约束

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

      使用多列索引时注意顺序和查询条件保持一致,同时删除不必要的单列索引

    合适的数据类型:

      使用可存下数据的最小的数据类型

      使用简单的数据类型

      使用合理的字段属性长度,固定长度的表会更快

      尽可能使用not  null定义字段

      尽量少用text,非用不可最好分表

    选择合适的索引列:

      查询频繁的列,在where、group by、order by、on从句中出现的列

      where条件中<、<=、=、>、>=、between、in 以及 like 字符串+通配符(%)出现的列

      长度小的列,索引字段越小越好,因为数据库的存储单位是页,一页中能存下的数据越多越好

      离散度大的列,放在联合索引前面。查看离散度,通过统计不同的列值来实现,count越大,离散程度越高

      

    单库的性能优化:

    SQL的优化:

      使用limit对查询结果的记录进行限定

      避免select *, 将需要查找的字段列出来

      使用连接( join ) 来代替子查询

      拆分大的delete 或 insert 语句

      可通过开启慢查询日志来找出较慢的SQL

      不做列运算,select  id  where  age + 1 = 10,任何对列的操作都将导致表扫描,它包括数据库教程函数、计算表达式等等,查询时要尽可能将操作移至等号右边。

      sql语句尽可能简单,一条sql只能在一个cpu运算,大语句拆成小语句,减少锁的时间,一条大的sql可以堵死整个库

      OR改写成IN:OR的效率是N级别,IN的效率是log(n) 级别,in的个数建议控制在200以内

      不用函数和触发器,在应用程序实现

      避免%xxx式查询

      少用JOIN

      使用同类型进行比较,比如用 ‘123’ 和 ‘123’ 比,123 和 123 比

      尽量避免在WHERE字句中使用 != 或者 <> 操作符,否则引擎将放弃使用索引而进行全表扫描

      对于连续数值,使用BETWEEN不用IN: select  id  from  t  where  num  between 1 and 5

      列表数据不要拿全表,要使用limit来分页,每页数量也不要太大

    分区:

      分区是一种简单的水平拆分,用户需要在建表的时候加上分区参数,对应用是透明的无需修改代码

      对用户来说,分区表是一个独立的逻辑表,但是底层由多个物理子表组成,实现分区的代码实际上是通过对一组底层表的对象封装,但对SQL层来说是一个完全封装底层的黑盒子。mysql实现分区的方式也意味着索引也是按照分区的子表定义,没有全局索引

      用户的SQL语句是需要针对分区表做优化,SQL条件中要带上分区条件的列,从而使查询定位到少量的分区上,否则就会扫描全部分区,可以通过EXPLAIN  PARTITIONS 来查看某条SQL语句会落在哪些分区上,从而进行SQL优化

    分区的好处:

      可以让单表存储更多的数据

      分区表的数据更容易维护,可以通过清除整个分区批量删除大量数据,也可以增加新的分区来支持新插入的数据。另外还可以对一个独立的分区进行优化、检查、修复等操作

      部分查询能够从查询条件上确定只落在少数分区上,速度会很快

      分区表的数据还可以分布在不同的物理设备上,从而高效利用硬件设备

      可以使用分区表来避免某些特殊瓶颈,例如InnoDB单个索引的互斥访问、ext3文件系统的inode竞争

      可以备份和恢复单个分区

    分区的限制和缺点:

      一个表只能有1024个分区

      如果分区字段中有主键或者唯一索引的列,那么所有主键列和唯一索引列都必须包含进来

      分区表无法使用外键约束

      NULL值会使分区过滤无效

      所有分区必须使用相同的存储引擎

    分区的类型:

      RANGE分区:基于属于一个给定连续区间的列值,把多行分配给分区

      LIST分区:类似于按RANGE分区,区别在于LIST分区是基于列值匹配一个离散值集合中的某个值来进行选择

      HASH分区:基于用户定义的表达式的返回值来进行选择的分区,该表达式使用将要插入到表中的这些行的列值进行计算,这个函数可以包含Mysql中有效的、产生非负整数值的任何表达式

      KEY分区:类似于按HASH分区,区别在于KEY分区只支持计算一列或者多列,且Mysql服务器提供其自身的哈希函数,必须有一列或者多列包含整数值

    按上述的优化方案优化后,还是查询卡死,则可以考虑分表了,把一次查询分成多次查询,然后把结果组合返回给用户。

      

  • 相关阅读:
    linux软件包安装yum
    linux软件包安装rpm
    使用OwnCloud建立属于自己私有的云存储网盘
    Linux 防火墙
    Linux docker
    llinux 权限2
    详列JDK中的设计模式(二)结构型
    详列JDK中的设计模式(一)创建型
    JavaWeb学习总结(一) JavaWeb基础与Tomcat服务器
    老生常谈-从输入url到页面展示到底发生了什么
  • 原文地址:https://www.cnblogs.com/wanmeishenghuo/p/13613070.html
Copyright © 2011-2022 走看看