日期:2013-07-06  浏览次数:20577 次

7.2.2 预算查询功用

在大多数情况下,可以通过统计磁盘搜索次数来预算查询的功用。对小表来说,通常情况下只需求搜索一次磁盘就能找到对应的记录(由于索引可能曾经缓存起来了)。对大表来说,大致可以这么预算,它使用B树做索引,想要找到一条记录大概需求搜索的次数为:log(row_count) / log(index_block_length / 3 * 2 / (index_length + data_pointer_length)) + 1。

在MySQL中,一个索引块通常是1024bytes,数据指针通常是4bytes。对于一个有500,000条记录、索引长度为3bytes(medium integer)的表来说,依据上面的公式计算得到需求做 log(500,000)/log(1024/3*2/(3+4)) + 1 = 4 次搜索。

这个表的索引大概需求 500,000 * 7 * 3/2 = 5.2MB的存储空间(假定典型的索引缓冲区的2/3),因此应该会有更多的索引在内存中,并且可能只需求1到2次调用就能找到对应的记录。

对于写来说,大概需求4次(甚至更多)搜索才能找到新的索引位置,更新记录时通常需求2次搜索。

请留意,前面的讨论中并没有提到使用程序的功用会由于log N的值越大而下降。只需所有的东西都能由操作系统或者SQL服务器缓存起来,那么功用只会由于数据表越大而稍微下降。当数据越来越大之后,就不能全部放到缓存中去了,就会越来越慢了,除非使用程序是被磁盘搜索约束的(它跟随着的log N值添加而添加)。为了避免这种情况,可以在数据量增大当前也随着增大索引缓存容量。对 MyISAM 类型表来说,索引缓存容量是由系统变量 key_buffer_size 控制的。概况请看"7.5.2 Tuning Server Parameters"。

7.2.3 SELECT 查询的速度

通常情况下,想要让一个比较慢的 SELECT ... WHERE 查询变得更快的第一件事就是,先检查看看能否可以添加索引。所有对不同表的访问都通常使用索引。可以使用 EXPLAIN 语句来判断 SELECT 使用了哪些索引。概况请看"7.4.5 How MySQL Uses Indexes"和"7.2.1 EXPLAIN Syntax (Get Information About a SELECT)"。

以下是几个常用的提高 MyISAM 表查询速度的忠告:

想要让MySQL将查询优化的速度更快些,可以在数据表曾经加载完全部数据后执行行 ANALYZE TABLE 或运转 myisamchk --analyze 命令。它更新了每个索引部分的值,这个值意味着相反记录的平均值(对于独一索引来说,这个值则不断都是 1)。MySQL就会在当你使用基于一个非恒量表达式的两表连接时,依据这个值来决定使用哪个索引。想要查看结果,可以在分析完数据表后运转 SHOW INDEX FROM tbl_name 查看 Cardinality 字段的值。myisamchk --description --verbose 显示了索引的分布信息。

想要依据一个索引来排序数据,可以运转 myisamchk --sort-index --sort-records=1 (如果想要在索引 1 上做排序)。这对于有一个独一索引并且想依据这个索引的顺序顺次读取记录的话来说是一个提高查询速度的好办法。不过要留意的是,第一次在一个大表上做排序的话将会耗费很长时间。

7.2.4 MySQL如何优化 WHERE 子句

这个章节讲述了优化程序如何处理 WHERE 子句。例子中使用了 SELECT 语句,但是在 DELETE 和 UPDATE 语句中对 WHERE 子句的优化是一样的。

留意,关于MySQL优化的任务还在继续,因此本章节还没结束。MySQL做了很多优化任务,而不只仅是文档中提到的这些。

MySQL的一些优化做法如下:

去除不必要的括号:

((a AND b) AND c OR (((a AND b) AND (c AND d))))

-> (a AND b AND c) OR (a AND b AND c AND d)

展开常量:

(a-> b>5 AND b=c AND a=5

去除常量条件(在展开常量时需求):

(B>=5 AND B=5) OR (B=6 AND 5=5) OR (B=7 AND 5=6)

-> B=5 OR B=6

常量表达示在索引中只计算一次

在单独一个表上做 COUNT(*) 而不使用 WHERE 时, 对于 MyISAM 和 HEAP 表就会直接从表信息中检索结果。在单独一个表上做任何表 NOT NULL 达式查询时也是这样做。