如果已经删除了表的一大部分,或者如果已经对含有可变长度行的表(含有VARCHAR、BLOB或TEXT列的表)进行了很多更改,则应使用OPTIMIZE TABLE命令来进行表优化。?这个命令可以将表中的空间碎片进行合并,并且可以消除由于删除或者更新造成的空间浪费,但OPTIMIZE TABLE命令只对MylSAM、BDB和InnoDB表起作用。
mysql> analyze table fa_order;
+------------------------+---------+----------+----------+
| Table | Op | Msg_type | Msg_text |
+------------------------+---------+----------+----------+
| zs_personcash.fa_order | analyze | status | OK |
+------------------------+---------+----------+----------+
1 row in set (0.03 sec)
对于InnoDB引擎的表来说,通过设置innodb_file_per_table参数,设置InnoDB为独立表空间模式,这样每个数据库的每个表都会生成一个宓立的云1文件,用于存储表的数据和索引,这样可以一定程度上减轻InnoDB表的空间回收问题。另外,在删除大量数据后,InnoDB表可以通过alter table但是不修改引擎的方式来回收不用的空间。
insert into table ( name , age , sex ) values ( 'stark', 30 , 1), ( 'yy', 30 , 2 ) ...
优化ORDER BY语句之前,首先来了解一下MySQL中的排序方式。
mysql> show index from fa_order;
+----------+------------+--------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+----------+------------+--------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| fa_order | 0 | PRIMARY | 1 | id | A | 5080802 | NULL | NULL | | BTREE | | |
| fa_order | 1 | pay_status | 1 | pay_status | A | 18 | NULL | NULL | YES | BTREE | | |
| fa_order | 1 | goodtype | 1 | goodtype | A | 18 | NULL | NULL | YES | BTREE | | |
| fa_order | 1 | user_id | 1 | user_id | A | 5080802 | NULL | NULL | | BTREE | | |
| fa_order | 1 | flag | 1 | flag | A | 18 | NULL | NULL | YES | BTREE | | |
| fa_order | 1 | ordersn | 1 | order_no | A | 5080802 | NULL | NULL | YES | BTREE | | |
| fa_order | 1 | consume_type | 1 | consume_type | A | 18 | NULL | NULL | YES | BTREE | | |
| fa_order | 1 | f_addtime | 1 | addtime | A | 1016160 | NULL | NULL | YES | BTREE | | 查询统计钱 |
| fa_order | 1 | f_addtime | 2 | flag | A | 1016160 | NULL | NULL | YES | BTREE | | 查询统计钱 |
+----------+------------+--------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
9 rows in set (0.06 sec)
第一种通过有序索引顺序扫描直接返回有序数据,这种方式在使用explain分析査询的时候显示为Using Index,不需要额外的排序,操作效率较高。
mysql> explain select id from fa_order order by id;
+----+-------------+----------+-------+---------------+---------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+-------+---------------+---------+---------+------+---------+-------------+
| 1 | SIMPLE | fa_order | index | NULL | PRIMARY | 8 | NULL | 5080802 | Using index |
+----+-------------+----------+-------+---------------+---------+---------+------+---------+-------------+
1 row in set (0.06 sec)
第二种是通过对返回数据进行排序,也就是通常说的Filesort排序,所有不是通过索引直接返回排序结果的排序都叫Filesort排序。Filesort并不代表通过磁盘文件进行排序,而只是说明进行了Filesort排序操作,至于排序操作是否使用了磁盘文件或临时表等,则取决于MySQL服务器对排序参数的设置和需要排序数据的大小。
mysql> explain select * from fa_order order by goodtype;
+----+-------------+----------+------+---------------+------+---------+------+---------+----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+------+---------------+------+---------+------+---------+----------------+
| 1 | SIMPLE | fa_order | ALL | NULL | NULL | NULL | NULL | 5080802 | Using filesort |
+----+-------------+----------+------+---------------+------+---------+------+---------+----------------+
1 row in set (0.05 sec)
Filesort是通过相应的排序算法,将取得的数据在sort_buffer_size系统变量设置的内存排序区中进行排序,如果内存装载不下,它就会将磁盘上的魏进行分块,再对各个数据块进行排序,然后将各个块合并成有序的结果集。sort_bufifer_size设置的排序区是每个线程独占的,所以同一个时刻,MySQL中存在多个sort buff排序区。
了解了MySQL排序的方式,优化目标就清晰了:尽量减少额外的排序,通过索引直接返回有序数据。WHERE条件和ORDER BY使用相同的索引,并且ORDER BY的顺序和索引顺序相同,并且ORDER BY的字段都是升序或者都是降序。否则肯定需要额外的排序操作,这样就会出现Filesort。
通过创建合适的索引能够减少Filesort出现,但是在某些情况下,条件限制不能让Filesort消失,那就需要想办法加快Filesort的操作。对于Filesort, MySQL有两种排序算法。
两次扫描算法(Two Passes):首先根据条件取出排序字段和行指针信息,之后在排序?区sort buffer中排序如果排序区sort buffer不够,则在临时表Temporary Table中存储排序结果.完成排序后根据行指针回表读取记录.该算法是MySQL4.1之前采用的算法,需要两次访问数据,第一次获取排序字段和行指针信息,第二次根据行指针获取记录,尤其是第二次读取操作可能导致大量随机I/O操作;优点是排序的时候内存开销较少。
一次扫描算法(Single Pass): 一次性取出満足条件的行的所有字段,然后在排序区sort buffer中排序后直接输出結果集.排序的时候内存开销比较大,但是排序效率比两次扫描算法美高。
MySQL通过比较系统变量max_lengfli_for_sort_data的大小和Query语句取出的字段总大小来判断使用哪种排序算法。如果max_length_for_sort_data更大,那么使用第二种优化之后的算法;否则使用第一种算法。
适当加大系统变量max_length_fbr_sort_data的值,能够让MySQL选择更优化的Filesort排序算法。当然,假如max_length_fdr_sort_data设置过大,会造成CPU利用率过低和磁盘I/O?过高,CPU和I/O利用平衡就足够了。
适当加大sort_buffer_size排序区,尽量让排序在内存中完成,而不是通过创建临时表放在文件中进行;当然屈不能无限制加大sort_buflfer_size排序区,因为sort_buffbr_size参数是每个线程独占的,设置过大,会导致服务器SWAP要考虑数据库活动连接成和服务器内存的?大小来适当设置排序区。
尽量只使用必要的字段,SELECT具体的字段名称,而不是SELECT*选择所有字段,这样可以减少排序区的使用,提高SQL性能。
默认情况下,MySQL对所有GROUP BY coll,col2,…的字段进行排序。这与在査询中指定 ORDER BY coll,co!2,…类似。因此,如果显式包括包含相同列的ORDER BY子句,则对MySQL的实际执行性能没有什么影响。
如果査询包括GROUP BY但用户想要避免排序结果的消耗测可以指定ORDER BY NULL 禁止排序。
MySQL 4.1开始支持SQL的子査询。这个技术可以使用SELECT语句来创建一个单列的?査询结果,然后把这个结果作为过滤条件用在另一个査询中。使用子査询可以一次性地完成很多逻辑上需要多个步骤才能完成的SQL操作,同时也可以避免事务或者表锁死,并且写起来也很容易。但是,有些情况下,子査询可以被更有效率的连接(JOIN)替代。