• 索引优化

索引创建

CREATE [UNIQUE] INDEX indexName ON mytable(columnname(length));

ALTER mytable ADD [UNIQUE] INDEX [indexName] ON (columnname(length));

索引删除

DROP INDEX [indexName]  ON mytable;

查看索引

SHOW INDEX FROM mytable;

优势:

1.类似图书馆建书目索引,提高数据检索的效率,降低数据库的IO成本

2.通过索引对数据进行排序,降低数据库的排序成本,降低了CPU的消耗

劣势:

  1. 实际上索引也是一张表,该表保存了主键与索引字段,并指向实体表的记录,所以索引也是占用空间的。
  2. 虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT,UPDATE,DELETE.因为更新表时,MYSQL不仅要保存数据,还要保存一下索引文件每次更新添加了索引列的字段,都会调整因为更新带来的键值变化后的索引信息。
  3. 索引只是提高效率的一个因素,如果你的MYSQL有大数据量的表,就需要花时间研究建立最优秀的索引,或优化查询。

哪些情况需要创建索引:

1.主键自动建立唯一索引

2.频繁作为查询条件的字段应该创建索引

3.查询中与其它表关联的字段,外键关系建立索引

4.频繁更新的字段不适合建索引

5.where条件里用不到的的字段不创建索引

6.单键/组合索引的选择问题(在高并发的下倾向创建组合索引)

7.查询中排序的字段,排序的字段若通过索引区访问,将大大提高排序速度

8.查询中统计或者分组的字段

哪些情况不需要建索引:

1.表的记录太少

2.经常增删改的字段

3.数据重复且分布平均的表字段

多表连接—Join 语句优化:

1.尽可能减少join 语句中的NestedLoop的循环总次数,永远用小结果集驱动大结果集。

2.优先优化NestedLoop的内存循环。

3.保证Join语句中被驱动表上的Join条件字段已经被索引。

4. 当无法保证被驱动表的Join条件字段被索引,且内存充足的情况下适当加大JoinBuffer大小的设置。

建索引的建议:

  1. 对于单键索引,尽量选择针对当前query过滤性更好的索引;
  2. 在选择组合索引的时候,当前的query中过滤性最好的字段在索引的字段顺序中位置越靠前越好;
  3. 在选择组合索引的时候,尽量选择可以能够包含当前query中where子句中更多字段的索引;
  4. 尽可能通过分析统计信息和调整query的写法来达到选择合适的索引的目的。

Order by优化:

Mysql支持两种方式的排序:FileSort和Index,Index效率高。Sql扫描索引本身完成排序,FileSort效率较低。

1.Order by子句,尽量使用index方式排序,避免使用fileSort方式排序

2.尽可能在索引列上完成排序操作,遵循索引建的最佳左前缀

3.如果不在索引列上,filesort有两种算法:双路排序和单路排序

双路排序:

Mysql 4.1 之前使用的是双路排序,字面意思是进行两次扫描磁盘,最终得到数据。

读取行指针和orderby列,对他们进行排序,然后扫描已经排序好的列表,按照列表中的值重新从列表中读取对应的数据输出。

从磁盘取排序字段,在buffer进行排序,再从磁盘取其它字段。

单路排序:

Mysql 4.1之后,出现了第二种改进算法, 就是单路排序。

从磁盘读取查询需要的所有的列,按照order by列在buffer对他们进行排序,然后扫描排序后的列表进行输出,它的效率更快一些,避免了第二次读取数据。并且把随机IO变成了顺序IO,但是他会使用更多的磁盘空间,因为他把每一行都保存在内存中了。

注意:

因为单路排序是一次把所有字段取出,所以可能取出数据的总大小超出sort_buffer的容量,导致没次只能取出sort_buffer容量大小的数据, 进行排序(创建tmp文件多路合并),拍完序再取出sort_buffer容量大小,再排, 从而导致多次IO。

优化策略:

增大sort_buffer_size参数的设置

增大max_length_for_sort_data参数的设置

增高oredr by的速度:

  1. Order by 时不要使用select * ,只select出需要的字段,在这里的影响是:

    1. 当Query的字段的大小总和小于max_length_for_sort_data而且排序字段不是TEXT/BLOB类型时,会用改进后的算法-单路排序,否则用老算法-多路排序。
    2. 两种算法的数据都有可能超出sort_buffer的容量,超出之后,会创建tmp文件进行合并排序,会导致多次IO,但是用单路排序算法的风险更大一些,所以要提高sort_buffer_size。
  2. 尝试提高sort_buffer_size

不管用哪种算法,提高这个参数都会提高效率,当然要根据系统的能力去提高,因为这个参数是针对每个进程的。

  1. 尝试提高max_length_for_sort_data

提高这个参数,会增加使用改进算法的概率。如果没有设的太高,数据总容量超出sort_buffer_size的概率就增大,明显症状的磁盘IO活动和低的处理器使用率。

为排序使用索引

Mysql两种排序方式:文件排序或扫描有序索引排序

Mysql能为排序与查询使用相同的索引

Group by关键字的优化:

group by分组之前必排序。

  1. Group by的实质是先排序,后进行分组,按照索引建的最佳左前缀
  2. 当无法使用索引列,增大sort_buffer_size、max_length_for_sort_data参数的设置
  3. Where高于having,能写在where子句下的限定条件就不要写在having下了。

为什么用B/B+树(平衡多路查找树)这种结构来实现索引呢??

系统从磁盘读取数据到内存时是以磁盘块(block)为基本单位的,位于同一个磁盘块中的数据会被一次性读取出来

局部性原理与磁盘预读:

实际过程中,磁盘并不是每次严格按需读取,而是每次都会预读。磁盘读取完需要的数据后,会按顺序再多读一部分数据到内存中,这样做的理论依据是计算机科学中注明的局部性原理:

当一个数据被用到时,其附近的数据也通常会马上被使用

程序运行期间所需要的数据通常比较集中

mysql是基于磁盘的数据库,索引是以索引文件的形式存在于磁盘中的,索引的查找过程就会涉及到磁盘IO消耗,磁盘IO的消耗相比较于内存IO的消耗要高好几个数量级,所以索引的组织结构要设计得在查找关键字时要尽量减少磁盘IO的次数。

(1)由于磁盘顺序读取的效率很高(不需要寻道时间,只需很少的旋转时间),

因此对于具有局部性的程序来说,预读可以提高I/O效率.预读的长度一般为页(page)的整倍数。

(2)MySQL(默认使用InnoDB引擎),将记录按照页的方式进行管理,每页大小默认为16K(这个值可以修改)。linux 默认页大小为4K。

B-Tree借助计算机磁盘预读的机制,并使用如下技巧:
    每次新建节点时,直接申请一个页的空间,这样就保证一个节点物理上也存储在一个页里,加之计算机存储分配都是按页对齐的,就实现了一个结点只需一次I/O。

假设 B-Tree 的高度为 h, B-Tree中一次检索最多需要h-1次I/O(根节点常驻内存),渐进复杂度为O(h)=O(logdN)O(h)=O(logdN)。

一般实际应用中,出度d是非常大的数字,通常超过100,因此h非常小(通常不超过3,也即索引的B+树层次一般不超过三层,所以查找效率很高)。

一棵高度为2的B+树,大概可以存放:2w条大小为1k的记录

一个高度为3的B+树大概可以存放:2000w条大小为1k的记录

为什么mysql的索引使用B+树而不是B树呢??
(1)B+树更适合外部存储(一般指磁盘存储),由于内节点(非叶子节点)不存储data,所以一个节点可以存储更多的内节点,每个节点能索引的范围更大更精确。也就是说使用B+树单次磁盘IO的信息量相比较B树更大,IO效率更高。
(2)mysql是关系型数据库,经常会按照区间来访问某个索引列,B+树的叶子节点间按顺序建立了链指针,加强了区间访问性,所以B+树对索引列上的区间范围查询很友好。而B树每个节点的key和data在一起,无法进行区间查找。

Explain

--建表

CREATE TABLE `emp` (

`id` int(11) NOT NULL AUTO_INCREMENT,

`dept_id` int(11),

`name` varchar(30),

`sex` char,

PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

CREATE TABLE `dept` (

`id` int(11) NOT NULL AUTO_INCREMENT,

`dept_name` varchar(30),

PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

CREATE TABLE `dept_location` (

`dept_id` int(11) NOT NULL AUTO_INCREMENT,

`location` varchar(30),

PRIMARY KEY (`dept_id`)

) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

CREATE TABLE `adress` (

`id` int(11) NOT NULL AUTO_INCREMENT,

`emp_id` int(11),

`address` varchar(30),

PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

insert into emp(dept_id,name,sex) values(1,'Jane','0');

insert into emp(dept_id,name,sex) values(2,'Mary','0');

insert into emp(dept_id,name,sex) values(1,'Jack','1');

insert into emp(dept_id,name,sex) values(3,'Leo','0');

insert into emp(dept_id,name,sex) values(1,'Ruby','0');

insert into dept(dept_name) values('Business');

insert into dept(dept_name) values('Market');

insert into dept(dept_name) values('Software');

insert into adress(emp_id,address) values(1,'深圳');

insert into adress(emp_id,address) values(2,'深圳');

insert into adress(emp_id,address) values(3,'深圳');

insert into adress(emp_id,address) values(4,'北京');

insert into adress(emp_id,address) values(5,'北京');

Select_type:

explain select emp.name,(select dept.dept_name from dept where dept.id = emp.dept_id) from emp;

explain select d1.name,(select id from adress) d2  

from  (select id,name from emp where sex ='0') d1

where d1.name  ='Mary'

union  

(select id,dept_name from dept);

Type:

explain select * from emp;

explain select * from emp where id = 1;

--eq_ref

explain select * from dept,dept_location where dept.id = dept_location.dept_id;

--ref  非唯一性索引扫描

create index idx_emp_name on emp(name);

explain select * from emp where name ='Mary';

--index

explain select id from emp;

--possible_keys key

explain select dept.*

from emp,dept,dept_location

where emp.id = dept.id and dept.id = dept_location.dept_id

and dept.dept_name = 'Business';

  1. 覆盖索引

create index idx_emp_ns on emp(name,sex);

explain select name ,sex from emp;

-- key_len

列类型

KEY_LEN

备注

id int

key_len = 4+1

int为4bytes,允许为NULL,加1byte

id bigint not null

key_len=8

bigint为8bytes

user char(30) utf8

key_len=30*3+1

utf8每个字符为3bytes,允许为NULL,加1byte

user varchar(30) not null utf8

key_len=30*3+2

utf8每个字符为3bytes,变长数据类型,加2bytes

user varchar(30) utf8

key_len=30*3+2+1

utf8每个字符为3bytes,允许为NULL,加1byte,变长数据类型,加2bytes

detail text(10) utf8

key_len=30*3+2+1

TEXT截取部分,被视为动态列类型。

说明:索引字段的附加信息:可以分为变长和定长数据类型讨论,当索引字段为定长数据类型时,如char,int,datetime,需要有是否为空的标记,这个标记占用1个字节(对于not null的字段来说,则不需要这1字节);对于变长数据类型,比如varchar,除了是否为空的标记外,还需要有长度信息,需要占用两个字节。

对于,char、varchar、blob、text等字符集来说,key len的长度还和字符集有关,latin1一个字符占用1个字节,gbk一个字符占用2个字节,utf8一个字符占用3个字节。

character set:utf8=3,gbk=2,latin1=1  len = 3

key_len的长度计算公式:

varchr(10)变长字段且允许NULL  =  10 * 3 + 1(NULL) + 2(变长字段)

varchr(10)变长字段且不允许NULL =  10 * 3 + 2(变长字段)

char(10)固定字段且允许NULL   =  10 * 3 + 1(NULL)

char(10)固定字段且不允许NULL =  10 * 3

--

Explain select * from dept , dept_location

where dept.id = dept_location.dept_id

and dept_location.location ='ac';

--建索引优化

create index idx_dl_location on dept_location(location);

Explain select * from dept , dept_location

where dept.id = dept_location.dept_id

and dept_location.location ='ac';

Extra:

CREATE TABLE `t1` (

`id` int(11) NOT NULL AUTO_INCREMENT,

`col2` int(11),

`col3` varchar(30),

`col4` char,

`col5` varchar(30),

PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

create index idx_t1_234 on t1(col2,col3,col4);

--using filesort

explain select col2 from t1 where col2 =5 order by col4;

--优化

explain select col2 from t1 where col2 =5 order by col3,col4;

--using temporary

explain select col3 from t1 where col2>2 group by col3 \G;

explain select col3 from t1 where col2>2 group by col2,col3 \G;

慢查询日志:

Mysql提供的一种日志记录,它用来记录mysql中响应时间超过阈值(long_query_time)的语句.

long_query_time的默认值为10, 即记录运行10s以上的语句。

开启MySQL的慢查询日志功能
默认情况下,MySQL是没有开启慢查询日志的。要开启这个功能,

Show variables like ‘%slow_query_log%’;

默认10s

开启:

Set global slow_query_log = 1

只对当前的数据库生效,如果mysql重启之后会失效。

show global status like ‘%Slow_queries%’;   查询当前系统有哪些慢查询sql

如果要永久生效:

我们需要修改MySQL的配置文件,windows下修改my.ini,Linux下修改my.cnf文件,在[mysqld]最后增加如下命令:

slow_query_log
long_query_time = 1

slow_query_log_file = filepath

最后一个参数指定慢查询日志的文件存放路径,没有指定的话,系统默认会给一个缺省的文件:
host_name-slow.log

*如果不是调优需要,一般不建议启动该参数,因为开启慢查询日志或多或少会带来一定的性能影响*

Mysql提供的日志分析工具:mysqldumpslow

如:mysqldumpslow -s r -t 10 /var/lib/,ysql/slow.log

Show Profile:

是mysql提供可以用来分析当前会话中语句执行的资源消耗情况。可以用于sql的调优的测量。

默认情况下参数处于关闭状态,并保存最近15次的运行结果。

https://dev.mysql.com/doc/refman/5.5/en/show-profile.html

  show variables like '%profiling%';

set profiling = on;

  运行sql

开启之后,查询的sql就会被记录;

查看结果

 Show profiles;

      诊断sql:

     Show profile cpu, block io for query <查询的id>;

比较耗内存/时间的四个操作:

Converting HEAP to MyISAM 查询结果太大, 内存都不够用了往磁盘上搬。

Creating tmp table创建临时表

Coping to tmp table on disc 把内存中临时表复制到磁盘

locked

全局查询日志:
   set global general_log = 1;

set global log_output = ‘table’;

此后,查询的sql都会记录在mysql数据库里的general_log表,可以用下面的命令查看:

Select * from mysql.general_log;

**永远不要在生产环境开启这个功能。

二、InnoDB锁

InnoDB与MyISAM的最大不同有两点:一是支持事务(TRANSACTION);二是采用了行级锁。

数据库事务隔离级别:

在并发事务处理带来的问题中,“更新丢失”通常应该是完全避免的。但防止更新丢失,并不能单靠数据库事务控制器来解决,需要应用程序对要更新的数据加必要的锁来解决,因此,防止更新丢失应该是应用的责任。

“脏读”、“不可重复读”和“幻读”,其实都是数据库读一致性问题,必须由数据库提供一定的事务隔离机制来解决。数据库实现事务隔离的方式,基本可以分为以下两种。

  • READ UNCOMMITTED(未提交读)

在这种隔离级别下,事物中的修改,即使没有提交,对其他失误也都是可见的。

事务可以读取未提交的数据,这也被称为脏读(Dirty Read)。一般在实际应用中很少使用。

  • READ COMMITTED(提交读)

一个事务开始时,只能“看见”已经提交的事务所做的修改。换句话说,一个事务从开始到提交之前,所做的任何修改对其它事务都是不可见的。这个级别也叫做不可重复读,因为在一个事务中两次执行同样的查询,可能会得到不一样的结果。 大多数数据库系统默认的隔离级别都是READ COMMITTED(但mysql不是)。

  • REPEATABLE READ(可重复读)

解决了脏读和不可重复读的问题,保证了在同一个事务当中多次读取同样的记录的结果是一致的。但是可能存在幻读的问题。InnoDB和XtraDB存储引擎通过多版本并发控制(MVCC)解决了幻读的问题。可重复读是mysql的默认事务隔离级别。

  • SERIALIZATION(可串行化)

是最高的隔离级别。它通过强制事务串行执行,避免了前面说的幻读的问题。SERIALIZATION会在读取的每一行的数据上都加上锁,所以可能导致大量的超时和锁争用的问题。实际应用中也很少用到这个隔离级别,只要在非常需要保证数据一致性的情况而且接收没有并发的情况下,才考虑该级别。

数据库的事务隔离越严格,并发副作用越小,但付出的代价也就越大,因为事务隔离实质上就是使事务在一定程度上 “串行化”进行,这显然与“并发”是矛盾的。同时,不同的应用对读一致性和事务隔离程度的要求也是不同的,比如许多应用对“不可重复读”和“幻读”并不敏 感,可能更关心数据并发访问的能力。

为了解决“隔离”与“并发”的矛盾,ISO/ANSI SQL92定义了4个事务隔离级别,每个级别的隔离程度不同,允许出现的副作用也不同,应用可以根据自己的业务逻辑要求,通过选择不同的隔离级别来平衡 “隔离”与“并发”的矛盾。下表很好地概括了这4个隔离级别的特性。

InnoDB的行锁模式及加锁方法

-- 加锁

lock table mylock read, class write;

-- 解锁

unlock tables;

读锁: 当前session对锁定表的查询操作可以执行,对其它表的任何操作都不可执行

其它session对当前表的查询操作可以执行,对当前表的更新操作不可以执行

写锁:当前session对锁定表的查询+更新+插入操作都可以执行,对其它表的任何操作都不可执行;

其它session对锁定表的查询被阻塞,需要等待锁被释放。

总结: 读锁会阻塞写, 但是不会阻塞读。而写锁则会把读和写都堵塞。

间隙锁:

当我们使用范围条件而不是相等条件检索数据,并请求共享锁或排他锁时,InnoDB 会给复合条件的已有数据记录的索引项加锁;对于在条件范围内但是不存在的记录叫做“间隙(GAP)”,

InnoDB也会给这个“间隙”加锁, 这种锁机制就是所谓的间隙锁(Next-Key锁)。

影响:

因为Query执行过程中,通过范围查找的话,他会锁定整个范围内所有的索引键值,即使这个键不存在。在锁定的过程中,无法往锁定范围内插入任何数据。

GAP锁,就是RR隔离级别,相对于RC隔离级别,不会出现幻读的关键。确实,GAP锁锁住的位置,也不是记录本身,而是两条记录之间的GAP。所谓幻读,就是同一个事务,连续做两次当前读 (例如:select * from t1 where id = 10 for update;),那么这两次当前读返回的是完全相同的记录 (记录数量一致,记录本身也一致),第二次的当前读,不会比第一次返回更多的记录 (幻象)。

如何保证两次当前读返回一致的记录,那就需要在第一次当前读与第二次当前读之间,其他的事务不会插入新的满足条件的记录并提交。为了实现这个功能,GAP锁应运而生。

如何分析行锁定:

通过检查InnoDb_row_lock状态变量来分析系统上的行锁的争夺情况。

Show status like 'Innodb_row_lock%';

Innodb_row_lock_current_waits: 当前正在等待锁定的数量;

Innodb_row_lock_time: 从系统启动到现在, 锁定时间的总长度;

Innodb_row_lock_time_avg: 每次等待所花的平均时间;

Innodb_row_lock_time_max:从系统启动到现在等待最长的一次所花的时间;

Innodb_row_lock_waits:从系统启动到现在总共等待的次数。

优化建议:

  • 尽可能让所有数据检索都通过索引来完成,避免无索引行锁升级为表锁;
  • 合理设计索引,尽量缩小锁的范围
  • 尽可能较少的索引条件,避免间隙锁
  • 尽量控制事务大小,减少锁定资源量和时间长度
  • 尽可能降低事务的隔离级别

CREATE TABLE `mylock` (

  `id` int(11) NOT NULL AUTO_INCREMENT,

  `name` varchar(30),

   PRIMARY KEY (`id`)

) ENGINE=MyISAM;

insert into mylock(name) values('a');

insert into mylock(name) values('b');

insert into mylock(name) values('c');

insert into mylock(name) values('d');

insert into mylock(name) values('e');

insert into mylock(name) values('f');

insert into mylock(name) values('g');

--读锁

lock table mylock read;

select * from mylock;

Session 1

update mylock set name ='s' where id=1;

Session 2    --读阻塞写

update mylock set name ='s' where id=1;

Session1释放读锁,session2写成功

--写锁:

间隙锁:

CREATE TABLE `innodb_lock` (

`id` int(11) NOT NULL,

`name` varchar(30),

PRIMARY KEY (`id`)

) ENGINE=INNODB;

insert into innodb_lock values(1,'a');

insert into innodb_lock values(3,'b');

insert into innodb_lock values(4,'c');

insert into innodb_lock values(5,'d');

insert into innodb_lock values(6,'e');

insert into innodb_lock values(7,'f');

insert into innodb_lock values(8,'g');

--session 1

Set auto_commit = 0;

update innodb_lock set name ='update' where id>1 and id<4;

--session 2

insert into innodb_lock values(2,'b');
--session 1

Commit;

Id为2 的记录虽然不存在,但是这行间隙也会被锁住。

三、主从复制:

  1. master将改变记录到二进制日志(binary log)。这些记录过程叫做二进制日志事件,binary log events;
  2. Slave将binary log events拷贝到它的中继日志(relay log);
  3. Slave重做中继日志中的事件,将改变应用到自己的数据库中,MYSQL的复制是异步的且串行化的。

主从复制解决的问题:

  1. 数据分布

    可以随意的停止或开始复制,并在不同的地理位置来分布数据备份,例如不同的数据中心。

  1. 负载均衡
        可以将读操作分布到多个服务器上,实现对读密集型应用的优化。(DNS轮询,网络负载均衡...)
  2. 备份
  3. 高可用和故障切换
         能够帮助应用程序避免MYSQL单点失败,发生故障时可以通过切换数据库缩短宕机时间。
  4. Mysql升级测试
         使用一个更高版本的MYSQL作为备库,保证在升级全部实例前,查询能够在备库按照预期执行。

原理:

基于语句的复制:

在mysql 5.0及之前的版本中只支持基于语句的复制(也称为逻辑复制),基于语句复制的模式下,主库会记录那些造成数据更改的查询,当备库读取到并重放这些事件的时候,实际上是把主库上执行过得sql再执行一遍。

基于行的复制

mysql 5.1开始支持基于行的复制,这种方式会将实际数据记录在二进制日志中。

复制的基本原则:

每个Slave只有一个master;

每个Slave只能有一个唯一的服务器id;

每个master可以有多个Slave。

一主一从最常见。

主从复制配置过程:

主节点:

  1. 启用二进制日志。
  2. 为当前节点设置一个全局唯一的server_id。
  3. 创建有复制权限的用户账号 REPLIACTION SLAVE ,REPLIATION CLIENT。

从节点:

  1. 启动中继日志。
  2. 为当前节点设置一个全局唯一的server_id。
  3. 使用有复制权限的用户账号连接至主节点,并启动复制线程。

分库、分表:

当用户量级上来后,写请求越来越多,该怎么办?加一个Master是不能解决问题的, 因为数据要保存一致性,写操作需要2个master之间同步,相当于是重复了,而且更加复杂。

这时就需要用到分库分表(sharding),对写操作进行切分。

用户请求量太大

因为单服务器TPS,内存,IO都是有限的。

解决方法:分散请求到多个服务器上; 其实用户请求和执行一个sql查询是本质是一样的,都是请求一个资源,只是用户请求还会经过网关,路由,http服务器等。

单库太大

单个数据库处理能力有限;单库所在服务器上磁盘空间不足;

单库上操作的IO瓶颈 解决方法:切分成更多更小的库

单表太大

CRUD都成问题;索引膨胀,查询超时

解决方法:切分成多个数据集更小的表。

分库分表的方式方法:

一般就是垂直切分和水平切分,这是一种结果集描述的切分方式,是物理空间上的切分。

然后是单个库太大,这时我们要看是因为表多而导致数据多,还是因为单张表里面的数据多。

分库:如果是因为表多而数据多,使用垂直切分,根据业务切分成不同的库。

分表: 如果是因为单张表的数据量太大,这时要用水平切分,即把表的数据按某种规则切分成多张表,甚至多个库上的多张表。

分库分表的顺序应该是先垂直分,后水平分

垂直拆分

垂直分表

也就是“大表拆小表”,基于列字段进行的。一般是表中的字段较多,将不常用的, 数据较大,长度较长(比如text类型字段)的拆分到“扩展表“。一般是针对那种几百列的大表,也避免查询时,数据量太大造成的“跨页”问题。

垂直分库

垂直分库针对的是一个系统中的不同业务进行拆分,比如用户User一个库,商品Producet一个库,订单Order一个库。 切分后,要放在多个服务器上,而不是一个服务器上。为什么? 我们想象一下,一个购物网站对外提供服务,会有用户,商品,订单等的CRUD。没拆分之前, 全部都是落到单一的库上的,这会让数据库的单库处理能力成为瓶颈。按垂直分库后,如果还是放在一个数据库服务器上, 随着用户量增大,这会让单个数据库的处理能力成为瓶颈,还有单个服务器的磁盘空间,内存,tps等非常吃紧。 所以我们要拆分到多个服务器上,这样上面的问题都解决了,以后也不会面对单机资源问题。

数据库业务层面的拆分,和服务的“治理”,“降级”机制类似,也能对不同业务的数据分别的进行管理,维护,监控,扩展等。 数据库往往最容易成为应用系统的瓶颈,而数据库本身属于“有状态”的,相对于Web和应用服务器来讲,是比较难实现“横向扩展”的。 数据库的连接资源比较宝贵且单机处理能力也有限,在高并发场景下,垂直分库一定程度上能够突破IO、连接数及单机硬件资源的瓶颈。

水平拆分

水平分表

针对数据量巨大的单张表(比如订单表),按照某种规则(RANGE,HASH取模等),切分到多张表里面去。 但是这些表还是在同一个库中,所以库级别的数据库操作还是有IO瓶颈。不建议采用。

水平分库分表

将单张表的数据切分到多个服务器上去,每个服务器具有相应的库与表,只是表中数据集合不同。 水平分库分表能够有效的缓解单机和单库的性能瓶颈和压力,突破IO、连接数、硬件资源等的瓶颈。

水平分库分表切分规则

  1. RANGE

从0到10000一个表,10001到20000一个表;

  1. HASH取模

一个商场系统,一般都是将用户,订单作为主表,然后将和它们相关的作为附表,这样不会造成跨库事务之类的问题。 取用户id,然后hash取模,分配到不同的数据库上。

  1. 地理区域

比如按照华东,华南,华北这样来区分业务,七牛云应该就是如此。

  1. 时间

按照时间切分,就是将6个月前,甚至一年前的数据切出去放到另外的一张表,因为随着时间流逝,这些表的数据 被查询的概率变小,所以没必要和“热数据”放在一起,这个也是“冷热数据分离”。

https://www.cnblogs.com/mfmdaoyou/p/7246711.html

MySQL深入了解与性能优化相关推荐

  1. 读薄《高性能MySql》(四)查询性能优化

    读薄<高性能MySql>(一)MySql基本知识 读薄<高性能MySql>(二)Scheme与数据优化 读薄<高性能MySql>(三)索引优化 读薄<高性能M ...

  2. Mysql批量插入更新性能优化

    Mysql批量插入更新性能优化 对于数据量较大的插入和更新,因io/cpu等性能瓶颈,会产生大量的时间消耗,目前主流的优化主要包括预编译.单条sql插入多条数据.事务插入等,下面详细介绍一下: 单条插 ...

  3. 【性能优化】MySQL 数据库连接原理和性能优化 - 学习/实践

    1.应用场景 学习MySQL数据库连接原理和性能优化, 开发高性能程序. 2.学习/操作 1. 文档阅读 MySQL 数据库连接原理和性能优化 - 高性能 MySQL 实战 | Laravel 学院 ...

  4. 浅析Mysql Join语法以及性能优化

    在讲MySQL的Join语法前还是先回顾一下联结的语法,呵呵,其实连我自己都忘得差不多了,那就大家一起温习吧,这里我有个比较简便的记忆方法,内外联结的区别是内联结将去除所有不符合条件的记录,而外联结则 ...

  5. mysql笔记03 查询性能优化

    查询性能优化 1. 为什么查询速度会慢? 1). 如果把查询看作是一个任务,那么它由一系列子任务组成,每个子任务都会消耗一定的时间.如果要优化查询,实际上要优化其子任务,要么消除其中一些子任务,要么减 ...

  6. mysql join 与 cross join 效率_浅析Mysql Join语法以及性能优化

    在讲MySQL的Join语法前还是先回顾一下联结的语法,呵呵,其实连我自己都忘得差不多了,那就大家一起温习吧,这里我有个比较简便的记忆方法,内外联结的区别是内联结将去除所有不符合条件的记录,而外联结则 ...

  7. 熟悉mysql数据库设计和性能优化_Mysql数据库性能优化

    Mysql数据库性能优化,可以从下面三点入手: 数据库设计 SQL语句优化 架构优化 一.数据库设计优化 1.适度的违反范式,适度    遵循三大范式就会带来查询时经常需要join,导致查询效率降低 ...

  8. mysql客户端工具_性能优化-理解 MySQL 体系结构(MySQL分库分表)

    实例和数据库 我们通常所说的 MySQL 数据库服务器由一个实例(instance)以及一个数据库(database)组成.实例包括一组后台进程/线程和许多内存结构,用于管理数据库:数据库由一组磁盘文 ...

  9. mysql 慢查询优化_MySQL 性能优化之慢查询

    性能优化的思路 首先需要使用慢查询功能,去获取所有查询时间比较长的SQL语句 其次使用explain命令去查询由问题的SQL的执行计划(脑补链接:点我直达1,点我直达2) 最后可以使用show pro ...

  10. 【MySQL】日志与性能优化

    是什么? 是最流行的关系型数据库管理系统 关系数据库是建立在关系模型基础上的数据库,借助于集合代数等数学概念和方法来处理数据库中的数据 mysql的优点: 1.性能卓越服务稳定,很少出现异常宕机 2. ...

最新文章

  1. java 写入mysql blob_java 读取写入 mysql blob
  2. hdu-2553 N皇后问题(深搜 + 状态压缩)
  3. 泛型DAO与泛型Service
  4. 获取Class类对象的三种方式
  5. Django 的工程创建
  6. linux底行模式显示信息,14天linux命令加强
  7. spring源码分析第三天------spring核心IOC容器和依赖注入原理
  8. php转型mysql dba_MySQL_DBA整理(转)
  9. mybatis接口动态代理原理
  10. 缩时摄影制作软件——GlueMotion for Mac支持m1
  11. 入侵排查篇---勒索病毒自救指南
  12. 网页端接入海康监控摄像头画面
  13. Qt MDI及其使用方法
  14. 编写第一个操作WORD文档的应用程序
  15. B. Wilbur and Array
  16. 特斯拉看位置说服务器错误,特斯拉App惊现大面积宕机!车主集体发飙,官方处理太弱智了...
  17. win10无线信号强度测试软件,如何在Win10 1909上确定Wi-Fi信号强度
  18. 100ms的SQL把服务器搞崩溃了
  19. word表格跨页多出一根线(三线表)
  20. 【智能制造】博创智能注塑生产智能化应用之路

热门文章

  1. 国际短信群发有哪些优势?
  2. 正大国际期货:你身边有朋友或者亲人做期货挣钱的没有?
  3. ANSYS渡槽槽身动水压力的施加(1)——矩形渡槽
  4. Java学习——复习 第八天 Swing程序设计、AWT绘图、事件监听
  5. 125款程序员专属情人节表白网站【建议收藏】HTML+CSS+JavaScript
  6. 中央财经的计算机类学什么时候,2019年3月全国计算机等级考试中央财经大学考试点报名通知...
  7. cs231n 2018系列笔记(lecture7)
  8. 【Python实战】再分享一款商品秒杀小工具,我已经把压箱底的宝贝拿出来啦~
  9. 医院如何实施WiFi建设方案
  10. Jlink命令行烧录