第一部分:SQL语句优化
1、尽量避免使用select *,使用具体的字段代替*,只返回使用到的字段。
2、尽量避免使用in 和not in,会导致数据库引擎放弃索引进行全表扫描。
SELECT * FROM t WHERE id IN (2,3)SELECT * FROM t1 WHERE username IN (SELECT username FROM t2)
优化方式:如果是连续数值,可以用between代替。如下:
SELECT * FROM t WHERE id BETWEEN 2 AND 3
如果是子查询,可以用exists代替。如下:
SELECT * FROM t1 WHERE EXISTS (SELECT * FROM t2 WHERE t1.username = t2.username)
3、尽量避免在字段开头模糊查询,会导致数据库引擎放弃索引进行全表扫描。如下:
SELECT * FROM t WHERE username LIKE '%li%'
优化方式:尽量在字段后面使用模糊查询。如下:
SELECT * FROM t WHERE username LIKE 'li%'
4、尽量避免进行null值的判断,会导致数据库引擎放弃索引进行全表扫描。如下:
SELECT * FROM t WHERE score IS NULL
优化方式:可以给字段添加默认值0,对0值进行判断。如下:
SELECT * FROM t WHERE score = 0
5、尽量避免在where条件中等号的左侧进行表达式、函数操作,会导致数据库引擎放弃索引进行全表扫描。如下:
SELECT * FROM t2 WHERE score/10 = 9SELECT * FROM t2 WHERE SUBSTR(username,1,2) = 'li'
优化方式:可以将表达式、函数操作移动到等号右侧。如下:
SELECT * FROM t2 WHERE score = 10*9SELECT * FROM t2 WHERE username LIKE 'li%'
6.当只要一行数据时使用LIMIT 1
加上LIMIT 1可以增加性能。MySQL数据库引擎会在查找到一条数据后停止搜索,而不是继续往后查询下一条符合条件的数据记录
7、使用连接(JOIN)来代替子查询(Sub-Queries)
8、在建有索引的字段上尽量不要使用函数进行操作
例如,在一个DATE类型的字段上使用YEAE()函数时,将会使索引不能发挥应有的作用。
9、排序的索引问题
mysql查询只使用一个索引,因此如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。因此数据库默认排序可以符合要求的情况下不要使用排序操作;尽量不要包含多个列的排序,如果需要最好给这些列创建复合索引。
10、应尽量避免在 where 子句中使用 != 或 <> 操作符,否则将引擎放弃使用索引而进行全表扫描。
11、应尽量避免在 where 子句中使用 or 来连接条件,如果一个字段有索引,一个字段没有索引,将导致引擎放弃使用索引而进行全表扫描,如:
select id from t where num=10 or Name = 'admin'
可以这样查询:
select id from t where num = 10union allselect id from t where Name = 'admin'
12、索引应建立在那些将用于JOIN,WHERE判断和ORDERBY排序的字段上。尽量不要对数据库中某个含有大量重复的值的字段建立索引。
比如性别可能就只有两个值,建索引不仅没什么优势,还会影响到更新速度,这被称为过度索引。
第二部分:数据库索引
1、索引的创建、查看、删除
//创建索引有两种方式:1.CREATE TABLE语句时可以创建索引 2.单独用CREATE INDEX或ALTER TABLE来为表增加索引// 1、ALTER TABLE 用来创建普通索引、唯一索引、主键索引和全文索引ALTER TABLE table_name ADD INDEX index_name (column_list);ALTER TABLE table_name ADD UNIQUE (column_list);ALTER TABLE table_name ADD PRIMARY KEY (column_list);ALTER TABLE table_name ADD FULLTEXT (column_list);// 2、CREATE INDEX可对表增加普通索引或UNIQUE索引以及全文索引,但是不可以对表增加主键索引CREATE INDEX index_name ON table_name (column_list);CREATE UNIQUE index_name ON table_name (column_list);CREATE FULLTEXT index_name ON table_name (column_list);
查看索引mysql> show index from tblname;mysql> show keys from tblname;
删除索引删除索引的mysql格式 :DORP INDEX IndexName ON tab_name;
2、使用索引的优缺点
创建索引可以大大提高系统的性能, 可以大大加快数据的检索速度。
索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有 必要。
第一, 创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。第二, 索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那么需要的空间就会更大。第三, 当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度。
一般来说,应该在这些列上创建索引。第一, 在经常需要搜索的列上,可以加快搜索的速度;第二, 在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构;第三, 在经常用在连接的列上,这些列主要是一些外键,可以加快连接的速度;第四, 在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的;第五, 在经常需要排序的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间;第六, 在经常使用在WHERE子句中的列上面创建索引,加快条件的判断速度。
一般来说,不应该创建索引的的这些列具有下列特点:第一,在查询中很少使用列不应该创建索引。第二,对于只有很少数据值的列也不应该增加索引。这是因为,由于这些列的取值很少,例如人事表的性别列,在查询的结果中,结果集的数据行占了表中数据行的很大比例,即需要在表中搜索的数据行的比例很大。增加索引,并不能明显加快检索速度。第三,对于那些定义为text, image和bit数据类型的列不应该增加索引。这是因为,这些列的数据量要么相当大,要么取值很少。第四,当修改性能远远大于检索性能时,不应该创建索引。这是因为,修改性能和检索性能是互相矛盾的。当增加索引时,会提高检索性能,但是会降低修改性能。当减少索引时,会提高修改性能,降低检索性能。因此,当修改性能远远大于检索性能时,不应该创建索引。
3、组合索引
组合索引的生效原则是 从前往后依次使用生效,如果中间某个索引没有使用,那么断点前面的索引部分起作用,断点后面的索引没有起作用;
造成断点的原因:
前边的任意一个索引没有参与查询,后边的全部不生效。
前边的任意一个索引字段参与的是范围查询,后面的不会生效。
断点跟索引字字段在SQL语句中的位置前后无关,只与是否存在有关。
where a=3 and b=45 and c=5 .... #这种三个索引顺序使用中间没有断点,全部发挥作用;where a=3 and c=5... #这种情况下b就是断点,a发挥了效果,c没有效果where b=3 and c=4... #这种情况下a就是断点,在a后面的索引都没有发挥作用,这种写法联合索引没有发挥任何效果;where b=45 and a=3 and c=5 .... #这个跟第一个一样,全部发挥作用,abc只要用上了就行,跟写的顺序无关
(a,b,c) 三个列上加了联合索引(是联合索引 不是在每个列上单独加索引)而是建立了a,(a,b),(a,b,c)三个索引,另外(a,b,c)多列索引和 (a,c,b)是不一样的。
(0) select * from mytable where a=3 and b=5 and c=4;#abc三个索引都在where条件里面用到了,而且都发挥了作用(1) select * from mytable where c=4 and b=6 and a=3;#这条语句为了说明 组合索引与在SQL中的位置先后无关,where里面的条件顺序在查询之前会被mysql自动优化,效果跟上一句一样(2) select * from mytable where a=3 and c=7;#a用到索引,b没有用,所以c是没有用到索引效果的(3) select * from mytable where a=3 and b>7 and c=3;#a用到了,b也用到了,c没有用到,这个地方b是范围值,也算断点,只不过自身用到了索引(4) select * from mytable where b=3 and c=4;#因为a索引没有使用,所以这里 bc都没有用上索引效果(5) select * from mytable where a>4 and b=7 and c=9;#a用到了 b没有使用,c没有使用(a使用的是范围查询)(6) select * from mytable where a=3 order by b;#a用到了索引,b在结果排序中也用到了索引的效果,前面说了,a下面任意一段的b是排好序的(7) select * from mytable where a=3 order by c;#a用到了索引,但是这个地方c没有发挥排序效果,因为中间断点了,使用 explain 可以看到 filesort(8) select * from mytable where b=3 order by a;#b没有用到索引,排序中a也没有发挥索引效果
在查询时,MYSQL只能使用一个索引,如果建立的是多个单列的普通索引,在查询时会根据查询的索引字段,从中选择一个限制最严格的单例索引进行查询。别的索引都不会生效。
第三部分:MySQL优化:explain分析
Explain是Mysql的自带查询优化器,负责select语句的优化器模块,可以模拟优化器执行SQL查询语句,从而知道Mysql是如何处理SQL的,语法也很简单:Explain + SQL
1、id:反映的是表的读取的顺序,或查询中执行select子句的顺序。
小表永远驱动大表,三种情况:
(1)id相同,执行顺序是由上至下的
(2)id不同,如果是子查询,id序号会递增,id值越大优先级越高,越先被执行
(3)id存在相同的,也存在不同的,所有组中,id越大越先执行,如果id相同的,从上往下顺序执行
derived是衍生虚表的意思,derived2中的2对应id2
2、select_type:反映的是Mysql理解的查询类型
(1)simple:简单的select查询,查询中不包含子查询或union。
(2)primary:查询中若包含任何复杂的字部分,最外层查询标记为primary。
(3)subquery:select或where列表中的子查询。
(4)derived(衍生):在from列表中包含的子查询,Mysql会递归执行这些子查询,把结果放在临时表里。
(5)union:若第二个select出现在union后,则被标记为union,若union包含在from字句的子查询中,外层select将被标记为derived
(6)union result:union后的结果集
3、table:反映这一行数据是关于哪张表的
4、type:访问类型排序
反映sql优化的状态,至少达到range级别,最好能达到ref
查询效率:system > const > eq_ref > ref > range > index > all
(完整的排序:system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index >all)
(1)system:从单表只查出一行记录(等于系统表),这是const类型的特例,一般不会出现
(2)const:查询条件用到了常量,通过索引一次就找到,常在使用primary key或unique索引中出现。
where id=1写死,所以类型是const
(3)eq_ref:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配,常见于主键或唯一索引扫描。
(4)ref:非唯一性索引扫描,返回匹配某个单独值的所有行,本质上也是一种索引访问,它可能会找到多个符合条件的行,与eq_ref的差别是eq_ref只匹配了一条记录。
(5)range:只检索给定范围的行,使用一个索引来选择行。key列显示使用了哪个索引,一般是在where语句中出现了between、、in等的查询。
这种范围扫描索引扫描比全表扫描要好,因为它只需要开始于索引的某一点,而结束于另一点,不用扫描全部索引。与eq_ref和ref的区别在于筛选条件不是固定值,是范围。
(6)index:full Index scan,index和all的区别为index类型只遍历索引树。这通常比all快,因为索引文件通常比数据文件小。
要获得的id信息,刚好id在索引上,从索引中读取
(all和index都是读全表,但index是从索引中读取的,而all是从硬盘中读的)
(7)all:全表扫描,如果查询数据量很大时,全表扫描效率是很低的。
5、possible_keys、key、key_len:反映实际用到了哪个索引,索引是否失效
(1)possible_keys:Mysql推测可能用到的索引有哪些,但不一定被查询实际使用
(2)key:实际使用的索引,若为null,则可能没建索引或索引失效。
(查询中若使用了覆盖索引,则该索引仅出现在key列表中。
覆盖索引:select后面的字段和所建索引的个数、顺序一致)
(3)key_len:表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度。同样的查询结果下,长度越短越好。
key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的。
6、ref:反映哪些列或常量被用于查找索引列上的值
7、rows:根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要读取的行数
仅通过主键索引查找是641行
建完相关的复合索引再查,需要查询的行数就变少了
8、Extra
(1)using filesort:mysql中无法利用索引完成的排序,这时会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。
创建索引时就会对数据先进行排序,出现using filesort一般是因为order by后的条件导致索引失效,最好进行优化。
order by的排序最好和所建索引的顺序和个数一致
(2)using temporary:使用了临时表保存中间结果,mysql在对查询结果排序时使用临时表。常见于排序order by和分组查询group by。
影响更大,所以要么不建索引,要么group by的顺序要和索引一致
(3)using index:表示相应的select操作中使用了覆盖索引,避免访问了表的数据行,效率好
覆盖索引:select后的数据列只从索引就能取得,不必读取数据行,且与所建索引的个数(查询列小于等于索引个数)、顺序一致。
所以如果要用覆盖索引,就要注意select的列只取需要用到的列,不用select *,同时如果将所有字段一起做索引会导致索引文件过大,性能会下降。
出现using where,表明索引被用来执行索引键值的查找
如果没有同时出现using where,表明索引用来读取数据而非执行查找动作。
(4)using where:表明使用了where过滤
(5)using join buffer:使用了连接缓存
(6)impossible where:where子句的值是false
(7)select tables optimized away
(8)distinct:优化distinct操作,在找到第一匹配的元组后即停止找同样值的动作
第四部分:数据库性能优化
一方面可以单台运行多个MySQL实例让服务器性能发挥到最大化,另一方面是对数据库进行优化,往往操作系统和数据库默认配置都比较保守,会对数据库发挥有一定限制,可对这些配置进行适当的调整。
4.1 数据库配置优化
MySQL常用有两种存储引擎,一个是MyISAM,不支持事务处理,读性能处理快,表级别锁。另一个是InnoDB,支持事务处理(ACID),设计目标是为处理大容量数据发挥最大化性能,行级别锁。
表锁:开销小,锁定粒度大,发生死锁概率高,相对并发也低。
行锁:开销大,锁定粒度小,发生死锁概率低,相对并发也高。
使用InnoDB存储引擎是最好的选择。
InnoDB参数默认值:
innodb_buffer_pool_size = 128M#索引和数据缓冲区大小,一般设置物理内存的60%-70%innodb_buffer_pool_instances = 1 #缓冲池实例个数,推荐设置4个或8个innodb_flush_log_at_trx_commit = 1 #关键参数,0代表大约每秒写入到日志并同步到磁盘,数据库故障会丢失1秒左右事务数据。1为每执行一条SQL后写入到日志并同步到磁盘,I/O开销大,执行完SQL要等待日志读写,效率低。2代表只把日志写入到系统缓存区,再每秒同步到磁盘,效率很高,如果服务器故障,才会丢失事务数据。对数据安全性要求不是很高的推荐设置2,性能高,修改后效果明显。innodb_file_per_table = OFF #默认是共享表空间,共享表空间idbdata文件不断增大,影响一定的I/O性能。推荐开启独立表空间模式,每个表的索引和数据都存在自己独立的表空间中,可以实现单表在不同数据库中移动。innodb_log_buffer_size = 8M#日志缓冲区大小,由于日志最长每秒钟刷新一次,所以一般不用超过16M
4.2 系统内核优化
大多数MySQL都部署在linux系统上,所以操作系统的一些参数也会影响到MySQL性能,以下对linux内核进行适当优化。
net.ipv4.tcp_fin_timeout = 30#TIME_WAIT超时时间,默认是60snet.ipv4.tcp_tw_reuse = 1 #1表示开启复用,允许TIME_WAIT socket重新用于新的TCP连接,0表示关闭net.ipv4.tcp_tw_recycle = 1 #1表示开启TIME_WAIT socket快速回收,0表示关闭net.ipv4.tcp_max_tw_buckets = 4096 #系统保持TIME_WAIT socket最大数量,如果超出这个数,系统将随机清除一些TIME_WAIT并打印警告信息net.ipv4.tcp_max_syn_backlog = 4096#进入SYN队列最大长度,加大队列长度可容纳更多的等待连接
在linux系统中,如果进程打开的文件句柄数量超过系统默认值1024,就会提示“too many files open”信息,所以要调整打开文件句柄限制。
# vi /etc/security/limits.conf #加入以下配置,*代表所有用户,也可以指定用户,重启系统生效* soft nofile 65535* hard nofile 65535# ulimit -SHn 65535 #立刻生效
4.3 硬件配置
加大物理内存,提高文件系统性能。linux内核会从内存中分配出缓存区(系统缓存和数据缓存)来存放热数据,通过文件系统延迟写入机制,等满足条件时(如缓存区大小到达一定百分比或者执行sync命令)才会同步到磁盘。也就是说物理内存越大,分配缓存区越大,缓存数据越多。当然,服务器故障会丢失一定的缓存数据。
SSD硬盘代替SAS硬盘,将RAID级别调整为RAID1+0,相对于RAID1和RAID5有更好的读写性能(IOPS),毕竟数据库的压力主要来自磁盘I/O方面。
第五部分:数据库架构扩展
5.1 主从复制
分为同步复制和异步复制,实际复制架构中大部分为异步复制。复制的基本过程如下:
1)Slave上面的IO进程连接上Master,并请求从指定日志文件的指定位置(或者从最开始的日志)之后的日志内容;
2)Master接收到来自Slave的IO进程的请求后,通过负责复制的IO进程根据请求信息读取制定日志指定位置之后的日志信息,返回给Slave 的IO进程。返回信息中除了日志所包含的信息之外,还包括本次返回的信息已经到Master端的bin-log文件的名称以及bin-log的位置;
3)Slave的IO进程接收到信息后,将接收到的日志内容依次添加到Slave端的relay-log文件的最末端,并将读取到的Master端的 bin-log的文件名和位置记录到master-info文件中,以便在下一次读取的时候能够清楚的告诉Master“我需要从某个bin-log的哪个位置开始往后的日志内容,请发给我”;
4)Slave的Sql进程检测到relay-log中新增加了内容后,会马上解析relay-log的内容成为在Master端真实执行时候的那些可执行的内容,并在自身执行。
主要搭建配置步骤:
(1)修改master,slave服务器
master服务器配置:
vi /usr/local/mysql/etc/my.cnf
[mysqld]
server-id=202 #设置服务器唯一的id,默认是1,我们设置ip最后一段,slave设置203
log-bin=mysql-bin # 启用二进制日志
#binlog-ignore-db = mysql,information_schema #忽略写入binlog的库
slave服务器配置:
vi /usr/local/mysql/etc/my.cnf
[mysqld]
server-id=203
replicate-do-db = abc #只同步abc库
slave-skip-errors = all #忽略因复制出现的所有错误(2)在主服务器上建立帐户并授权slave
mysql> mysql -u root -p123.commysql> GRANT REPLICATION SLAVE ON *.* to ‘sync’@‘192.168.1.2’ identified by ‘1234.com’; #replication:复制
(3)配置从数据库
mysql> change master to
-> master_host='192.168.0.202',
-> master_user='sync',
-> master_password='1234.com',
-> master_log_file='mysql-bin.000002',
-> master_log_pos=263;
#Log和pos是master上随机获取的。这段也可以写到my.cnf里面。
(4)启动slave同步进程并查看状态
mysql> start slave;
其中Slave_IO_Running 与 Slave_SQL_Running 的值都必须为YES,才表明状态正常。
(5)查看主数据库状态
mysql> show master status;
+------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000002 | 263 | | |
+------------------+----------+--------------+------------------+
(6)验证主从同步
在主mysql创建数据库abc,再从mysql查看已经同步成功。
5.2 MySQL Proxy 实现读写分离
大多数企业是在代码层面实现读写分离,另一个种方式通过代理程序实现读写分离,常见代理程序有MySQL Proxy、Amoeba。在这样数据库集群架构中,大大增加数据库高并发能力,解决单台性能瓶颈问题。如果从数据库一台从库能处理2000 QPS,那么5台就能处理1w QPS。
基本原理是让主数据库处理写方面事务,让从库处理SELECT查询。
主服务器Master:192.168.0.202
从服务器Slave:192.168.0.203
调度服务器MySQL-Proxy:192.168.0.204
(1)安装mysql-proxy
下载:http://dev.mysql.com/downloads/mysql-proxy/
(2)配置mysql-proxy,创建主配置文件
cd /usr/local/mysql-proxymkdir lua #创建脚本存放目录mkdir logs #创建日志目录cp share/doc/mysql-proxy/rw-splitting.lua ./lua #复制读写分离配置文件cp share/doc/mysql-proxy/admin-sql.lua ./lua #复制管理脚本vi /etc/mysql-proxy.cnf #创建配置文件[mysql-proxy]user=root #运行mysql-proxy用户admin-username=proxy #主从mysql共有的用户admin-password=123.com #用户的密码proxy-address=192.168.0.204:4000 #mysql-proxy运行ip和端口,不加端口,默认4040proxy-read-only-backend-addresses=192.168.0.203 #指定后端从slave读取数据proxy-backend-addresses=192.168.0.202 #指定后端主master写入数据proxy-lua-script=/usr/local/mysql-proxy/lua/rw-splitting.lua #指定读写分离配置文件位置admin-lua-script=/usr/local/mysql-proxy/lua/admin-sql.lua #指定管理脚本log-file=/usr/local/mysql-proxy/logs/mysql-proxy.log #日志位置log-level=info #定义log日志级别,由高到低分别有(error|warning|info|message|debug)daemon=true #以守护进程方式运行keepalive=true #mysql-proxy崩溃时,尝试重启保存退出!chmod 660 /etc/mysql-porxy.cnf
(3)修改读写分离配置文件
vi /usr/local/mysql-proxy/lua/rw-splitting.luaif not proxy.global.config.rwsplit then proxy.global.config.rwsplit = { min_idle_connections = 4, #默认超过4个连接数时,才开始读写分离 max_idle_connections = 8, #默认8 is_debug = false }end
(4)启动mysql-proxy
/usr/local/mysql-proxy/bin/mysql-proxy --defaults-file=/etc/mysql-proxy.cnfnetstat -tupln | grep 4000 #已经启动tcp 0 0 192.168.0.204:4000 0.0.0.0:* LISTEN 1264/mysql-proxy关闭mysql-proxy使用:killall -9 mysql-proxy
(5)在主服务器创建proxy用户用于mysql-proxy使用,从服务器也会同步这个操作
mysql> grant all on *.* to 'proxy'@'192.168.0.204' identified by '123.com';
(6)测试读写分离
使用客户端连接mysql-proxy
mysql -u proxy -h 192.168.0.204 -P 4000 -p123.com
5.3 MySQL-MMM 实现主主复制
有时,面对大量写操作的应用时,单台写性能达不到业务需求。如果做双主,就会遇到数据库数据不一致现象,产生这个原因是在应用程序不同的用户会有可能操作两台数据库,同时的更新操作造成两台数据库数据库数据发生冲突或者不一致。在单库时MySQL利用存储引擎机制表锁和行锁来保证数据完整性,怎样在多台主库时解决这个问题呢?有一套基于perl语言开发的主从复制管理工具,叫MySQL-MMM(Master-Master replication managerfor Mysql,Mysql主主复制管理器),这个工具最大的优点是在同一时间只提供一台数据库写操作,有效保证数据一致性。
mmm_mond:监控进程,负责所有的监控工作,决定和处理所有节点角色活动。此脚本需要在监管机上运行。
mmm_agentd:运行在每个mysql服务器上的代理进程,完成监控的探针工作和执行简单的远端服务设置。此脚本需要在被监管机上运行。
mmm_control:一个简单的脚本,提供管理mmm_mond进程的命令。
mysql-mmm的监管端会提供多个虚拟IP(VIP),包括一个可写VIP,多个可读VIP,通过监管的管理,这些IP会绑定在可用mysql之上,当某一台mysql宕机时,监管会将VIP迁移至其他mysql。
在整个监管过程中,需要在mysql中添加相关授权用户,以便让mysql可以支持监理机的维护。授权的用户包括一个mmm_monitor用户和一个mmm_agent用户,如果想使用mmm的备份工具则还要添加一个mmm_tools用户。
5.4 增加缓存
给数据库增加缓存系统,把热数据缓存到内存中,如果缓存中有要请求的数据就不再去数据库中返回结果,提高读性能。缓存实现有本地缓存和分布式缓存,本地缓存是将数据缓存到本地服务器内存中或者文件中。分布式缓存可以缓存海量数据,扩展性好,主流的分布式缓存系统有memcached、redis,memcached性能稳定,数据缓存在内存中,速度很快,QPS可达8w左右。如果想数据持久化就选择用redis,性能不低于memcached。
5.5 分库
分库是根据业务不同把相关的表切分到不同的数据库中,比如web、bbs、blog等库。如果业务量很大,还可将切分后的库做主从架构,进一步避免单个库压力过大。
5.6 分表
数据量的日剧增加,数据库中某个表有几百万条数据,导致查询和插入耗时太长,怎么能解决单表压力呢?你就该考虑是否把这个表拆分成多个小表,来减轻单个表的压力,提高处理效率,此方式称为分表。
分表技术比较麻烦,要修改程序代码里的SQL语句,还要手动去创建其他表,也可以用merge存储引擎实现分表,相对简单许多。分表后,程序是对一个总表进行操作,这个总表不存放数据,只有一些分表的关系,以及更新数据的方式,总表会根据不同的查询,将压力分到不同的小表上,因此提高并发能力和磁盘I/O性能。
分表分为垂直拆分和水平拆分:
垂直拆分:把原来的一个很多字段的表拆分多个表,解决表的宽度问题。你可以把不常用的字段单独放到一个表中,也可以把大字段独立放一个表中,或者把关联密切的字段放一个表中。
水平拆分:把原来一个表拆分成多个表,每个表的结构都一样,解决单表数据量大的问题。
第六部分:开启慢查询日志
一旦开启慢日志查询会增加数据库的压力。
mysql> set global slow-query-log=on #开启慢查询功能mysql> set global slow_query_log_file='/var/log/mysql/mysql-slow.log'; #指定慢查询日志文件位置mysql> set global log_queries_not_using_indexes=on; #记录没有使用索引的查询mysql> set global long_query_time=1; #只记录处理时间1s以上的慢查询
第七部分:数据库备份