为了使这个查询的效率更高,给其中一个联结列添加索引并重新执行EXPLAIN语句:
mysql> ALTER TABLE t2 ADD INDEX (i2);mysql> EXPLAIN SELECT t1.i1, t2.i2 FROM t1, t2 WHERE t1.i1 = t2.i2G*************************** 1. row ***************************id: 1select_type: SIMPLEtable: t1type: ALLpossible_keys: NULLkey: NULLkey_len: NULLref: NULLrows: 1000Extra:*************************** 2. row ***************************id: 1select_type: SIMPLEtable: t2type: refpossible_keys: i2key: i2key_len: 5ref: sampdb.t1.i1rows: 10Extra: Using where; Using index
我们可以看到性能提高了。T1的输出没有改变(表明还是需要进行全表扫描),但是优化器处理t2的方式就有所不同了:
· 类型从ALL改变为ref,意味着可以使用参考值(来自t1的值)来执行索引查找,定位t2中合格的数据行。
· 参考值在参考(ref)字段中给出了:sampdb.t1.i1。
· 行数值从1000降低到了10,显示出优化器相信对于t1中的每一行,它只需要检查t2中的10行(这是一个悲观的估计值。实际上,在t2中只有一行与t1中数据行匹配。我们在后面会看到如何帮助优化器改善这个估计值)。数据行组合的全部估计值使1000×10=10000。它比前面的没有索引的时候估计出来的一百万好多了。
对t1进行索引有价值吗?实际上,对于这个特定的联结操作,扫描一张表是必要的,因此没有必要对t1建立索引。如果你想看到效果,可以索引t1.i1并再次运行EXPLAIN:
mysql> ALTER TABLE t1 ADD INDEX (i1);mysql> EXPLAIN SELECT t1.i1, t2.i2 FROM t1, t2 WHERE t1.i1 = t2.i2G*************************** 1. row ***************************id: 1select_type: SIMPLEtable: t1type: indexpossible_keys: i1key: i1key_len: 5ref: NULLrows: 1000Extra: Using index*************************** 2. row ***************************id: 1select_type: SIMPLEtable: t2type: refpossible_keys: i2key: i2key_len: 5ref: sampdb.t1.i1rows: 10Extra: Using where; Using index
上面的输出与前面的EXPLAIN的输出相似,但是添加索引对t1的输出有一些改变。类型从NULL改成了index,附加(Extra)从空的改成了Using index。这些改变表明,尽管对索引的值仍然需要执行全表扫描,但是优化器还是可以直接从索引文件中读取值,根据不需要使用数据文件。你可以从MyISAM表中看到这类结果,在这种情况下,优化器知道自己只询问索引文件就能够得到所有需要的信息。对于InnoDB 和BDB表也有这样的结果,在这种情况下优化器可以单独使用索引中的信息而不用搜索数据行。
我们可以运行ANALYZE TABLE使优化器进一步优化估计值。这会引起服务器生成键值的静态分布。分析上面的表并再次运行EXPLAIN得到了更好的估计值:
mysql> ANALYZE TABLE t1, t2;mysql> EXPLAIN SELECT t1.i1, t2.i2 FROM t1, t2 WHERE t1.i1 = t2.i2G*************************** 1. row ***************************id: 1select_type: SIMPLEtable: t1type: indexpossible_keys: i1key: i1key_len: 5ref: NULLrows: 1000Extra: Using index*************************** 2. row ***************************id: 1select_type: SIMPLEtable: t2type: refpossible_keys: i2key: i2key_len: 5ref: sampdb.t1.i1rows: 1Extra: Using where; Using index
在这种情况下,优化器估计在t2中与t1的每个值匹配的数据行只有一个。
重载优化过程
这个过程听起来多余,但是有时候你还是希望去掉某些MySQL优化行为的:
重载优化器的表联结次序。使用STRAIGHT_JOIN强迫优化器按照特定的次序使用数据表。在这样操作的时候,你必须对数据表进行排序,这样才能保证第一张表是被选择的行数最少的表。如果你不能确定被选择行数最少的是哪一张表,那么就把行数最多的放到第一的位置。换句话说,试着对表进行排序,使最有约束力的选择出现在最前面。你对可能的备选数据行缩小地越早,执行查询的性能就越好。请确保在带有STRAIGHT_JOIN和不带STRAIGHT_JOIN的时候分别执行该查询。有时候由于某些原因的存在,优化器没有按照你认定的方式联结数据表,STRAIGHT_JOIN也可能没有实际的帮助作用。
另一个可能性是在联结的数据表列表中的某个表的后面使用FORCE INDEX、USE INDEX和IGNORE INDEX调节符来告诉MySQL如何使用索引。这在优化器没有做出正确选择的时候是有用处的。
以最小的代价清空一张表。当需要完全地清空一张MyISAM数据表的时候,最快的方法是删除它并利用它的.frm文件中存储的脚本来重新建立它。使用TRUNCATE TABLE语句实现:
TRUNCATE TABLE tbl_name;
通过重新建立MyISAM数据表来清空它的这种服务器优化措施使该操作非常快,因为不需要单独地逐行删除。
但是TRUNCATE TABLE也带来了一些副作用,在某些环境中是不符合要求的:
· TRUNCATE TABLE不一定能够计算出被删除的数据列的精确数量。如果你需要这个数值,请使用不带WHERE子句的DELETE语句:
DELETE FROM tbl_name;
· 但是,通过重新建立来清空数据表,它可能会把序号的起始值设置为1。为了避免这种情况,请使用"不优化的"全表DELETE语句,它带有一个恒为真的WHERE子句:
DELETE FROM tbl_name WHERE 1;
添加WHERE子句会强迫MySQL进行逐行删除,因为它必须计算出每一行的值来判断是否能够删除它。这个语句执行的速度很慢,但是它却保留了当前的AUTO_INCREMENT序号。