数据库优化:
(1)SQL语句优化
(2)数据库设计优化
(3)参数优化
(4)硬件资源和文件系统
上面的顺序也表现了这4个工作对性能影响力的大小
(1)数据库(表)设计合理
符合3范式(有时需要适当的逆范式)
第一范式:1NF是对属性的原子性约束,要求属性具有原子性,不可再分解(
只要是关系型数据库都满足1NF)
第二范式:2NF是对记录的唯一性约束,要求记录有唯一标识,即表中记录不能有完全相同的。(一般通过设置主键)
第三范式:3NF是对字段冗余性的约束,即任何字段不能由其他字段派生出来,它要求字段没有冗余,没有冗余的数据库设计可以做到。但是没有冗余的数据库未必是最好的数据库,有时为了提高运行效率,就必须降低范式标准,适当保留冗余数据。(通常设置外键)
具体做法是:在概念数据模型设计时遵守第三范式,降低范式标准的工作放到物理数据模型设计时考虑,降低范式就是增加字段,允许冗余。
在1-n的表中,应当尽量将冗余放在1这边。
(2)文件系统
常见的文件系统有:EXT3、EXT4、XFS、ReiserFS
其中XFS和ReiserFS 性能较优,适用于海量小文件的读写。
也可以使用裸设备,所谓的裸设备就是没有格式化成文件系统的硬盘,相比于普通硬盘,裸设备没有缓存层,因此效率会高于普通硬盘。
问题:这里可能有人会说,普通硬盘有缓存层,不是可以加快读写速度吗?怎么反而说裸设备效率更高?
这是因为,其实格式化为文件系统后,都会有一个缓存层,而缓存层的作用是,防止写入的速度太快,而导致硬盘接受不了。于是,对硬盘写入数据的话,会写到缓存层,接着再写入到硬盘中。但是随着技术发展,硬盘能接受的速度已经接近于硬盘写入的速度,因此在需要的时候,可以去掉这个缓存层,把硬盘作为裸设备使用。
(3)硬件
常用的硬盘有SAR、FC、SSD
SSD 固态硬盘,使用闪存,随机读写性能好
SAR和FC 硬盘 ,这两种硬盘都有盘片,需要机械臂来读写,因此随机读写效率明显低于固态硬盘SSD
查看mysql 服务器的各种状态值可以使用下面的命令查看:
mysql > show global status;
如果要针对某项状态值查看,可以用:
mysql > show status like ‘查询值%';
mysql > show variables like '%查询值%';
===========================
1、慢查询
开启慢查询的好处是它能记录下所有执行超过long_query_time时间的SQL语句, 帮你找到执行慢的SQL, 方便我们对这些SQL进行优化。
打开慢日志:
(1)编辑my.cnf ,添加以下参数:
slow_query_log
slow_query_log_file = /data/mysql/server1-slow.log
long_query_time = 2 //最长执行时间
(2)
mysql >set
global
slow_query_log=
ON
;
mysql >
set global long_query_time=2;
打开慢查询日志可能对系统性能有一点影响,如果服务器的架构是主-从结构,可以考虑打开其中一台从服务器的慢查询日志,这样既可以监控慢查询,又不会对系统性能造成过大影响。另外,可以用mysql自带的命令mysqldumpslow进行查询。假如要查出最近访问次数最多的20个SQL语句:
# mysqldumpslow -s c -t 20 host - slow.log
-s, 是表示按照何种方式排序
c、t、l、r分别是按照记录次数、时间、查询时间、返回的记录数来排序
ac、at、al、ar,表示相应的倒序
-t, 是top n的意思,即为返回前面多少条的数据
-g, 后边可以写一个正则匹配模式,大小写不敏感的;
2、连接数
(1)最大连接数
如果经常遇见
mysql:ERROR 1040:Too many connections 的情况,一种情况是访问量确实过大,mysql服务器顶不住了,这时候应该考虑增加从服务器分散读的压力。另外一种情况,就是max_connections 的值设置的太小。
这台mysql服务器的最大连接数是151,然后查询一下该服务器响应的最大连接数:
如果最大响应连接数超过了最大连接数,则会出现1040的错误。
最大响应连接数一般占最大连接数85%左右。
修改方法:
> 在my.cnf 中修改max_connections 参数,并重启数据库
> set global max_connections=160;
(2)当前连接数
mysql> show status like '%Threads_connected%';
+-------------------+-------+
| Variable_name | Value |
+-------------------+-------+
| Threads_connected | 2 |
+-------------------+-------+
1 row in set (0.00 sec)
[root@localhost ~]# mysqladmin -uroot -p123456 status
Uptime: 493
Threads: 2 Questions: 17 Slow queries: 0 Opens: 33 Flush tables: 1 Open tables: 26 Queries per second avg: 0.034
(3)单个用户的最大连接数
可以通过参数max_user_connections显示单个用户的最大连接数,默认为0表示不限制。
3、key_buffer_size
key_buffer_size 是设置MyISAM表索引缓存空间的大小,此参数对MyISAM表性能影响最大。
可以看到这里分配了16MB内存给key_buffer_size
查看key_buffer_size 使用情况:
key_read_requests : 一共有n个索引读取请求
key_readds : 有n个请求在内存中没有找到,直接从硬盘上读取索引
索引未命中缓存的概率:
key_cache_miss_rate = key_reads / key_read_requests * 100%
如果key_cache_miss_rate 在0.1%(即每1000个请求有一个直接读取硬盘)以下,就算很好。
如果key_cache_miss_rate 在0.01%以下,说明key_buffer_size 分配得过多,可以适当减少。
4、临时表
当执行语句时,关于已经被创造了的隐含临时表的数量,我们可以用如下命令查询其具体情况:
每次创建临时表时,Created_tmp_tables 都会增加,如果是在磁盘上创建临时表,Created_tmp_disk_tables 也会增加。Created_tmp_files 表示mysql 服务创建的临时文件数,比较理想的配置是:
Created_tmp_disk_tables / Created_tmp_tables * 100% <=25%
查看MYSQL服务器对临时表的配置:
上图表示只有16MB以下的临时表才能全部放到内存中,超过的会用到磁盘临时表。
5、打开表的情况
Open_tables 表示打开表的数量,Opened_tables表示打开过的表的数量,可以用以下命令查看:
如果Opened_tables 数量过大,说明配置中table_open_cache(mysql5.1.3之前叫做table_cache)的值可能太小,查询服务器table_open_cache值:
比较合适的值:
Open_tables / Opened_tables * 100% >= 85%
Open_tables / table_cache * 100% <=95%
6、进程使用情况
如果我们在mysql服务器的配置文件中设置了thread_cache_size ,当客户端断开的时候,服务器处理此客户请求的线程将会缓存起来以响应下一个请求而不是销毁(前提是缓存数未达到上限)Thread_created 表示创建过的线程数,我们可以用以下的命令查看:
如果发现Threads_created 的值过大,表明mysql服务器一直在创建线程,这是比较消耗资源的,可以适当增大配置文件中thread_cache_size 的值。查询thread_cache_size 配置:
7、查询缓存(query_cache)
查询缓存主要涉及2个参数,一个是query_cache_size 设置Query_cache 的大小,一个是query_cache_type 是设置使用查询缓存的类型,我们可以用下面的命令查看:
开启query_cache :mysql> set global query_cache_size=1024*50;
下面解释一下参数:
Qcache_free_blocks //缓存中相邻内存块的个数,数目大说明可能有碎片。FLUSH QUERY CACHE 会对缓存中的碎片进行整理,从而得到一个空闲块。
Qcache_free_memory //缓存中空闲的内存
Qcache_hits //多少次命中
Qcache_inserts //插入次数,每次插入一个查询就增加1
Qcache_lowmem_prunes //多少条Query因为内存不足而被清除出Query Cache
Qcache_not_cached // 不适合进行缓存的查询数量,通常由于这些查询不是用select语句或者用了now()之类的函数
Qcache_queries_in_cache //当前缓存的查询(和响应)数量
Qcache_total_blocks //缓存中块的数量
查询query_cache 的配置命令:
参数解释:
query_cache_limit //超过此大小的查询将不会被缓存
query_cache_min_res_unit //缓冲块的最小值
query_cache_size //查询缓存大小
query_cache_type //缓存类型,决定缓存什么样的查询
query_cache_wlock_invalidate //表示当有其他客户端正在对MyISAM 表进行写操作时,度请求是要等到WRITE LOCK 释放资源后再查询是否允许直接从Query Cache中读取结果,默认为OFF(可以直接从query cache中取得结果)
注意:
query_cache_min_res_unit 默认为4KB,这个值设置大队大数据查询有好处,但如果你的查询都是小数据,则容易造成内存碎片和浪费。
查询缓存碎片率=Qcache_free_blocks /Qcache_total_blocks * 100%
如果超过20%,可以用FLUSH QUERY CACHE 整理缓存碎片,或者尝试减小query_cache_min_res_unit 的值。
查询利用率 = (query_cache_size - Qcache_free_memory )/query_cache_size * 100%
如果利用率在25%以下,说明query_cache_size设置的过大,可以适当减小;
如果利用率高于80%而且Qcache_lowmem_prunes >50 说明query_cache_size 可能有点小,或者碎片太多。
8、排序使用情况
它表示系统中数据进行排序时所使用的Buffer,可以通过以下命令查询:
Sort_merge_passes 包括如下步骤: mysql首先会尝试在内存中做排序,使用的内存大小由系统变量sort_buffer_size来决定,如果它不够大则所有记录都读到内存中,而mysql 则会把每次在内存中排序的结果存到临时文件中,等mysql找到所有记录之后,再把临时文件中的记录做一次排序。这次再排序就会增加sort_merge_passes。实际上,mysql会用另一个临时文件来存储再次排序的结果,所以我们通常会看到sort_merge_passes增加的数值是建临时文件数的2倍。因为用到了临时文件,所以速度可能会比较慢,增大sort_buffer_size会减少sort_merge_passes和创建临时文件的次数,但盲目的增大sort_buffer_size并不一定会提高速度。
9、文件打开数
一般情况下open_files 大于 open_files_limit 值时,mysql数据库就会发生卡住的现象,导致Apache服务器打不开相应页面,这个问题大家在工作中应注意,我们可以用如下命令查看:
比较合适的设置是:open_files / open_files_limit * 100% <=75%
10、Innodb_buffer_pool_size
Innodb存储引擎的缓存机制和MyISAM的最大区别就在于,Innodb不仅仅缓存索引,同时还会缓存数据。此参数用来设置Innodb最主要的buffer的大小,也就是缓存用户表及索引数据的最主要缓存空间,对Innodb整体性能影响也最大。
====================
SQL 语句优化
SQL语句的种类:
ddl(数据定义语言) [create alter drop]
dml(数据操作语言)[insert delete update]
dtl(数据事务语言)[commit rollback savepoint]
dcl(数据控制语言)[grant revoke]
select
show status 命令
该命令可以显示mysql数据库当前状态,我们主要关心的是"Com"开头的指令
show status like 'Com%'; == show session status like 'Com%'; // 显示当前控制台的情况
show global status like 'Com%'; // 显示数据库从启动到查询的次数
重点注意:Com_select , Com_insert , Com_update , Com_delete 通过这几个参数,可以很容易的了解到当前数据库的应用是以插入更新为主还是查询操作为主,以及各类SQL大致的执行比例是多少。
还有几个常见的参数:
Connections : 试图连接mysql服务器的基本情况
Uptime : 服务器工作的时间(单位:秒)
Slow_queries : 慢查询次数(默认是10)
大批量插入数据:
对于MyISAM
alter table table_name disable keys;
loading data;
alter table table_name enable keys;
也就是,在导入数据之前先关闭索引,不然每插入一条记录,由于数据改变了,需要另外的开销来维护索引,这将导致索引频繁的修改,因此,速度会较慢。
对于InnoDB
1. 将要导入的数据安装主键排序
2. set unique_check=0 关闭唯一性校验
3. set autocommit=0 关闭自动提交
MyISAM 和 InnoDB
1. MyISAM 不支持外键,Innodb支持
2. MyISAM 不支持事务,Innodb支持
3. 对数据信息的存储处理方式不同。
如果存储引擎是MyISAM 的,则创建一张表,对应三个文件*.MYI 、*.MYD. 、*.FRM
如果存储引擎是InnoDB,则创建一张表,对应一个文件*.frm,数据放在ibdata1
InnoDB 删除记录后,只是清空了数据,但是并没回收空间。
对于MyISAM 数据库,可以定时清理
mysql >optimize table table_name
对于InnoDB,则需要
1 使用mysqldump命令将InnoDB数据库导出
2 停止MySQL
3 删除所有InnoDB数据库文件和日志
4 启动MySQL并自动重建InnoDB数据库文件和日志文件
5 导入前面备份的数据库文件
常见的sql 优化手法
1. 优化group by 语句
默认情况下,mysql对所有的group by col1,col2进行排序,这与在查询中指定order by col1,col2类似。如果查询中包括group by 但用户想要避免排序结果的消耗,则可以使用order by null 禁止排序。
比如select * from dept group by dname order by null;
2. 有些情况下,可以使用连接来代替子查询。因为使用join,mysql不需要在内存中创建临时表
3. 如果想要在含有or的查询语句中利用索引,则or之间的每个条件列都必须用到索引,如果没有索引,则应该考虑增加索引
4. 在精度要求高的应用中,尽量使用定点数decimal
例如:
create table sal1(t1 float(10,2));
create table sal2(t1 decimal(10,2));