优化SELECT 语句和其它查询
首先,一个影响所有语句的因素:你的权限设置越复杂,你需要的开销越大。
当你用GRANT语句分配时使用简单的权限设置,这样可以让MySQL在客户端执行语句时
减小检查权限带来的开销。例如,如果你不授予任何表级或者列级的权限,服务器
就不需要检查tables_priv 和 columns_priv 表的目录,同样的,如果你不对
帐号设置资源限制,服务器就不需要进行资源计数,如果你有一个高查询列,
就值得简化授权结构来减小权限检查开销。
如果你的问题是一些特定的MySQL表达式或者函数,你可以在客户端用BENCHMARK()
函数来作计时测试,语法是:BENCHMARK(loop_count,expression).
例如:
mysql> SELECT BENCHMARK(1000000,1+1);
+------------------------+
| BENCHMARK(1000000,1+1) |
+------------------------+
| 0 |
+------------------------+
1 row in set (0.32 sec)
这个结果是在Pentium II 400MHz 的系统上得到的。这显示Mysql可以在这种系统上
0.32秒里执行1,000,000 次简单加法。
所有的MySQL函数应该都是优化过的,但是也有例外,BENCHMARK() 是个找出你的
查询是否有问题的强大工具。
EXPLAIN 语法(得到SELECT的信息)
EXPLAIN tbl_name
Or:
EXPLAIN SELECT select_options
EXPLAIN 语句可以被用作 DESCRIBE 的同义词或者可以作为得到MySQL怎样执行一个
语句的信息:
·EXPLAIN tbl_name 语法和DESCRIBE tbl_name 或者 SHOW COLUMNS FROM tbl_name
是同义的。
·当你在SELECT语句之前放上一个关键字EXPLAIN,MySQL会解释这个SELECT是怎样
执行的,提供表是如何连接和什么顺序。
本节介绍EXPLAIN的第二种用法。
通过EXPLAIN的帮助,你可以看到用索引来查找记录时你必须为表增加索引以增快
SELECT的速度。
如果你在不正确的索引用法上有问题,你应该运行ANALYZE TABLE来升级表统计,
比如 cardinality of keys, 这个会影响到optimizer的所作的选择。
你也可以看到是否optimizer 把表按照最优顺序联结,要让optimizer按照SELECT
语句里说的顺序来联结,用 SELECT STRAIGHT_JOIN 来代替SELECT。
EXPLAIN 返回一行SELECT语句中每个表的信息,表按照处理查询时MySQL读取他们
的顺序排列,MySQL使用single-sweep multi-join的方法解决所有的联结。这表示
MySQL 从第一个表读取一行,然后在第二个表里查找适配行,然后第三个表,等等。
当所有表处理完,它输出选定的列并从table列表里原路退回,直到有更多适配行
的表,就读取此表第二行并继续执行下一个表。
在MySQL4.1里,EXPLAIN 输出格式为了更好的同一些结构适应而改变,比如UNION
语句,子查询,derived tables,最值得注意的是两个新列的增加:
id 和 select_type,你用4.1之前的版本是看不到这两列的。
EXPLAIN 的每个输出行提供了一个表的信息。
估计查询的性能
大多数情况下,你可以通过计磁盘寻道次数来估计性能。对于小表,您通常可以
在一次磁盘寻道里找到那行(因为索引可能被cache了).对于大一些的表,你可以
估计出来用B-tree 索引你会需要这么多次寻道:log(row_count) / log
(index_block_length / 3 * 2 / (index_length + data_pointer_length)) + 1.
在MySQL里,一个索引块常常是1024字节,数据指针是4字节,对于一个索引占3字节
的500,000行的表,按公式可以得到log(500,000)/log(1024/3*2/(3+4)) + 1 = 4
次寻道。
这个索引需要占用的存储空间:500,000 * 7 * 3/2 = 5.2MB
(假定一个典型的索引填充率2/3), 所以大部分索引可能在内存里,而你大概只
需要一到两个访问读取数据找到需要的行。
对于写数据,你会需要4次寻道请求来找出存放新索引的位置,一般两次寻道来
更新索引并写入行。
注意前面的讨论并不表示你的程序的性能会根据 log N 慢慢衰减!只要所有东西
都被系统或者数据库cache,当表变大时只会慢一点点。当数据大到没法cache时,
就会变得很慢。要避免这个,可以增加key cache size,对于MyISAM的表,
key cache size 由系统变量 key_buffer_size 来控制。
SELECT 查询的速度
一般来说,当你想让SELECT ... WHERE 变快,第一件事就是看看你是否能加索引,
所有不同表之间的参照都应该通过索引来完成。你可以使用EXPLAIN语句来判断
SELECT 使用的是哪些索引。
一些加快MyISAM表查询的tips:
·要帮助MySQL优化查询,可以在一个表载入数据后使用ANALYZE TABLE 或者运行
myisamchk --analyze。This updates a value for each index part that
indicates the average number of rows that have the same value.
(For unique indexes, this is always 1.) MySQL will use this to decide
which index to choose when you join two tables based on a non-constant
expression. You can check the result from the table analysis by using
SHOW INDEX FROM tbl_name and examining the Cardinality value.
myisamchk --description --verbose shows index distribution information.
·按照索引分类索引和数据,使用 myisamchk --sort-index --sort-records=1
(如果你想归类索引1). This is a good way to make queries faster if you
have a unique index from which you want to read all records in order
according to the index. Note that the first time you sort a large table
this way, it may take a long time.