标签:设置 扩展 command 统计 for format mysql用户 mail xpl
MySQL数据库优化主要涉及两个方面,一方面是对SQL语句优化,另一方面是对数据库服务器和数据库配置的优化。
为了更好的看到SQL语句执行效率的差异,建议创建几个结构复杂的数据表,多导入一些数据进行测试,看到的效果比较直观。
尽量避免在列上进行运算,这样会导致索引失效。
优化前SELECT * FROM t WHERE YEAR(d)>=2011;
优化后SELECT * FROM t WHERE d>=‘2011-01-01‘;
使用JOIN时,应该用小结果集驱动大结果集。同时把复杂的JOIN查询拆分成多个Query。因为JOIN多个表时,可能导致更多的锁定和堵塞。
不建议:
SELECT * FROM a JOIN b ON a.id=b.id LEFT JOIN c ON c.time=a.date LEFT JOIN d ON c.pid=b.aid LEFT JOIN e ON e.cid=a.did;
注意LIKE模糊查询的使用,避免%%。
优化前SELECT * FROM t WHERE name LIKE ‘%de%‘;
优化后SELECT * FROM t WHERE name>=‘de‘ AND name<=‘df‘;
仅列出需要查询的字段,这对速度不会有明显的影响,主要考虑节省内存。
优化前SELECT * FROM member;
优化后SELECT id,name,pwd FROM member;
使用批量插入语句节省交互。
优化前:
1 | INSERT INTO t(id,name) VALUES(1,‘a‘); |
优化后INSERT INTO t(id,name) VALUES(1,‘a‘),(2,‘b‘),(3,‘c‘);
limit的基数比较大时,使用between。
优化前SELECT * FROM article ORDER BY id LIMIT 1000000,10;
优化后SELECT * FROM article WHERE id BETWEEN 1000000 AND 1000010 ORDER BY id;
between限定比limit快,所以在海量数据访问时,建议用between或where替换掉limit。但是between也有缺陷,如果id中间有断行或是中间部分id不读取的情况,总读取的数量会少于预计数量。
在取比较后面的数据时,通过desc方式把数据反向查找,以减少对前段数据的扫描,让limit的基数越小越好。
不要使用rand函数获取多条随机记录。
优化前SELECT * FROM table ORDER BY rand() LIMIT 20;
优化后SELECT * FROM
tableAS t1 JOIN (SELECT ROUND(ROUND()*((SELECT MAX(id) FROM
table) - (SELECT MIN(id) FROM
table)) + (SELECT MIN(id) FROM
table)) AS id ) AS t2 WHERE t1.id >= t2.id ORDER BY t1.id LIMIT 1 ;
这是获取一条随机记录,这样即使执行20次,也比优化前的sql语句高效。或者先用PHP产生随机数,把这个字符串传给MySQL,MySQL里用in查询。
不要使用COUNT(id),而应该使用COUNT(*)。
注意:个别情况,结果有变。
查看SQL语句执行效率
1 | mysql> SET @@profiling=1; |
对于同一条sql语句,第二次查询明显比第一次查询快,因为MySQL缓存做了查询。
查看第四条sql语句执行细节:
mysql> SHOW PROFILE FOR QUERY 4;
EXPLAIN
MySQL执行计划就是在一条SELECT语句前放上关键字EXPLAIN,MySQL解释它将如何处理SELECT,提供有关表如何联合和以什么次序联合的信息。
借助EXPLAIN可以知道:
优化器是否以一个最佳次序联合表。
注意:为了强制优化器对一个SELECT语句使用一个特定联合次序,需增加一个STRAIGHT_JOIN子句,方法如下:
EXPLAIN [EXTENDED] SELECT select_options
对比较复杂的查询进行计划分析时,可能会得到多条执行计划,如下:
1 | mysql> EXPLAIN SELECT * FROM user; |
各属性含义如下:
需要说明的是,type显示的访问类型是较为重要的指标,结果值从好到坏依次是:system(系统表)、const(读常量)、eq_ref(最多一条匹配结果,通常是通过主键访问)、ref(被驱动表索引引用)、fulltext(全文索引检索)、ref_or_null(带空值的索引查询)、index_merge(合并索引结果集)、unique_subquery(子查询中返回的字段是唯一组合或索引)、index_subquery(子查询返回的索引,但非主键)、range(索引范围扫描)、index(全索引扫描)、ALL(全表扫描)。
一般来说,保证查询至少达到range级,最好能达到ref级。ALL为全表扫描,是最坏的情况,这种情况往往是没用上索引。
MySQL索引建立和使用的基本原则如下:
关于MySQL索引的更多介绍,请参考MySQL索引
MySQL存储引擎
想要好的性能,第一步是选择合适的存储引擎。MySQL中常见的三种存储引擎是MyISAM、InnoDB和Memmory。
通常的观点是MyISAM注重性能,InnoDB注重事务,所以一般使用MyISAM的表做非事务型的业务。
这种观点产生于早期InnoDB还不成熟的时候,其实事实上并不是这样。MySQL在高并发下的性能瓶颈很明显,主要原因就是锁定机制导致的阻塞。而InnoDB在锁定机制上采用行级锁,不同于MyISAM的表级锁,行级锁在锁定上带来的消耗大于表级锁,但是在系统并发访问量较高时,InnoDB整体性能远高于MyISAM。同时,InnoDB的索引不仅缓存索引本身,也缓存数据,所以InnoDB需要更大的内存,现在内存是很廉价的。
存储引擎的选择方法
在介绍选择存储引擎之前,先来了解一下什么是读写比(R/W)。通过在数据库中执行SHOW GLOBAL STATUS
得到系统当前状态。在这些变量中,以Com_为前缀的变量表示某语句的执行次数,比如Com_select表示SELECT语句的执行次数,以此类推。通过计算读类型和写类型语句的比例,即可以确定一个大概的读写比例。理想的读写比例为100:1,当读写比达到10:1的时候,就认为是以写为主的数据库。一般来说,读写比在30:1左右。
选择存储引擎的原则如下:
MySQL服务器调整优化措施
关闭不必要的二进制日志和慢查询日志,仅在内存足够或开发调试时打开它们。
使用下面的语句查看查询是否打开:
SHOW VARIABLES LIKE ‘%slow%‘;
还可以使用下面的语句查看慢查询的条数,定期打开方便优化。
SHOW GLOBAL STATUS LIKE ‘%slow%‘;
但是慢查询也会带来一些CPU损耗。建议间断性打开慢查询日志来定位性能瓶颈。
增加MySQL允许的最大连接数。可用下面的语句查看MySQL允许的最大连接数。
SHOW VARIABLES LIKE ‘max_connections‘;
对于MyISAM表适当增加key_buffer_size。当前这需要根据key_cache的命中率进行计算。例如:
SHOW GLOBAL STATUS LIKE ‘key_read%‘;
key_cache_miss_rate = Key_reads / Key_read_requests * 100%
当key_cache_miss_rate值大于1%时就需要适当增加key_buffer_size了。
对于MyISAM,还需要注意table_cache的设置。当table_cache不够用的时候,MySQL会采用LRU算法踢掉最长时间没有使用的表;如果table_cache设置过小,MySQL就会反复打开、关闭FRM文档,造成一定性能的损失;如果table_cache设置过大,MySQL将会消耗很多CPU资源去处理table_cache算法。因此table_cache值一定要设置合理,可参考opened_tables参数的值,如果这个值一直增长,就需要适当增加table_cache值。
对于InnoDB,需要重点注意innodb_buffer_pool_size参数。
OPTIMIZE TABLE TableName
进行碎片整理。当MySQL单表数据量达到千万级以上时,无论如何对MySQL进行优化,查询如何简单,MySQL的性能都会明显降低,这时候可以采取以下措施:
为什么要反范式?
首先,要了解一下范式理论的背景。数据库范式理论是在20世纪70年代提出的,并且在20世纪80年代基本完善定型。那时候存储资源和网络资源都还不成熟。因此,当时数据库范式理论强调减少依赖、降低冗余。而现在存储资源和网络资源已不是问题,同时面临着高并发、极度复杂的业务逻辑,低延迟要求等情况下,还一味固执遵循范式设计理论是不当的。适当降低范式,增加冗余,用空间换时间是值得的。
通常在设计数据库是要遵循如下原则:
MySQL5.1及以上版本支持分区。数据库分区就是把一个数据表的文档和索引分散存储在不同的物理文档中。
查看数据库是否支持分区
5.1-5.5版本:SHOW VARIABLES LIKE ‘%partition%‘
5.6及以上版本:SHOW PLUGINS
查询结果中包含如下内容,表示支持分区。
1 | | partition | ACTIVE | STORAGE ENGINE | NULL | GPL | |
MySQL支持的分区类型包括Range、List、Hash、Key,其中Range最常用。
创建Range类型分区表
1 | mysql> CREATE TABLE member( |
添加分区
1 | mysql> ALTER TABLE member ADD PARTITION ( |
删除分区
1 | mysql> ALTER TABLE member DROP PARTITION member_3; |
检索information_schema数据库能看到刚刚创建的分区信息,检索方法如下:
1 | USE information_schema; |
此时,打开MySQL数据目录(SHOW VARIABLES LIKE ‘datadir‘
),如果MySQL配置文档设置innodb file per table 为ON(由于前面创建分区表时定义的是INNODB),则会发现:
1 | [root@localhost ~]# ll /usr/local/mysql/var/test/ |
由此可见,MySQL通过分区把数据保存到不同的数据文档里,同时索引也是分区的。相对于未分区的表来说,分区后单独的数据文档和索引文档的大小都明显降低,执行效率则明显提升。
验证执行效率
1 | # 插入几条数据 |
注意:使用分区功能后,相关的查询最好都用EXPLAIN PARTITIONS
过一遍,确认分区是否生效。
不过有些情况,比如说在主从结构中,因为主服务器由于很少使用SELECT查询,所以在主服务器上使用Range类型的分区通常并没有太大意义,此时使用Hash类型的分区相对更好。假设使用PARTITION BY HASH (id) PARTITIONS 10
,当插入新数据时,会根据id把数据平均分散到各个分区上(这里是10个分区),由于文档小,效率高,更新操作会变得更快。
创建HASH类型分区表
1 | mysql> CREATE TABLE blog ( |
验证
1 | # 插入几条数据 |
如何选择分区字段?
一般情况按照时间字段分区,不过具体情况还是应该按照需求而定。比如需求是按照用户和时间查询,哪种用的多就选哪种分区。如果使用主从结构,可以设计成不同的从服务器使用不同的分区字段,然后写个代理脚本,当执行查询时,通过代理脚本来决定选择正确的从服务器查询。
分区的缺点有哪些?
分库解决单台数据库并发访问压力,分表解决单表大数据量查询性能低。
垂直切分
水平切分
主从复制功能(读写分离)通过在主服务器和从服务器之间切分处理客户查询的负荷,可以得到更好的客户响应时间SELECT查询可以发送到从服务器,以降低主服务器的查询处理负荷。修改数据库的语句仍然发送到主服务器,以使主、从服务器保持同步。如果非更新查询为主(如SELECT查询),该负载均衡策略很有效。
MySQL主从复制的优点:
主从复制工作原理
主从复制过程
主从复制配置
mysql -V
命令查看版本号。REPLICATION SLAVE
权限。mysql> GRANT REPLICATION SLAVE ON *.* TO ‘repl‘ @ ‘%.mydomain.com‘ IDENTIFIED BY ‘123‘;
配置主服务器。
打开二进制日志,指定唯一Server ID。例如,在my.cnf配置文档中加入如下值:
1 | [mysqld] |
重启主服务器。
运行SHOW MASTER STATUS
语句,如图所示:
File表示主服务器正在使用binlog文档;Position的值与binlog文档的大小相同,表示下一个被记录事件的位置;Binlog_Do_DB和Binlog_Ignore_DB是主服务器控制写入binlog文档内容的过滤选项,默认为空,表示不做任何过滤。
配置从服务器。
从服务器的配置与主服务器类似,必须提供唯一的Server ID(不能和主服务器Server ID相同),配置完毕后同样需要重启MySQL从服务器,配置如下:
1 | [mysqld] |
启动从服务器。
接下来让从服务器连接主服务器,并开始重做主服务器binlog文档中的事件。
指定主服务器信息。
使用CHANGE MASTER TO
语句指定主服务器的信息,不要在配置文档中设置。下面语句可以替代在配置文档中提供主服务器信息,而且不需要停止服务器便可以为从服务器指定不同主服务器。
1 | mysql> CHANGE MASTER TO MASTER_HOST=‘192.168.1.100‘, |
此处指定MASTER_LOG_POS的值为0,因为要从日志的开始位置开始读。
查看从服务器的设置是否正确。
使用SHOW SLAVE STATUS
语句查看从服务器的设置是否正确:
1 | mysql> SHOW SLAVE STATUSG; |
Slave_IO_State、Slave_IO_Running和Slave_SQL_Running表明从服务器还没有开始复制过程。
注意:日志位置为4而不是0,因为0只是日志文档的开始位置,并不是日志记录事件的开始位置。实际上,MySQL知道的第一个事件的位置是4.
连接主从服务器
START SLAVE
语句开始复制:msyql> START SLAVE;
运行SHOW SLAVE STATUS
查看输出结果:
1 | mysql> SHOW SLAVE STATUSG; |
从结果看出,从服务器的I/O线程和SQL线程都已经开始运行,而且Seconds_Behind_Master不再是Null。日志位置增加意味着一些事件被获取并执行。如果在主服务器上进行修改,可以在从服务器上看到各种日志文档位置变化,以及数据库中数据的变化。
使用SHOW PROCESSLIST
语句查看主、从服务器的线程状态。
在主服务器上,可以看到从服务器的I/O线程创建的l连接:
1 | mysql> SHOW PROCESSLISTG; |
第2行就是处理从服务器的I/O线程的连接。
在从服务器上运行SHOW PROCESSLIST
语句。
1 | mysql> SHOW PROCESSLISTG; |
第一行为I/O线程状态,第二行为SQL线程状态。
注意:从服务器t通过读主服务器的二进制日志实现自我更新,对数据库进行修改的操作都要放在主服务器上执行,而从服务器只用来查询(只读不写的数据库操作)。
标签:设置 扩展 command 统计 for format mysql用户 mail xpl
原文地址:https://www.cnblogs.com/lijianming180/p/12014099.html