mysql 强制走索引

查询是数据库技术中最经常使用的操做。查询操做的过程比较简单,首先从客户端发出查询的SQL语句,数据库服务端在接收到由客户端发来的SQL语句后, 执行这条SQL语句,而后将查询到的结果返回给客户端。虽然过程很简单,但不一样的查询方式和数据库设置,对查询的性能将会有很在的影响。数据库

所以,本文就在MySQL中经常使用的查询优化技术进行讨论。讨论的内容如:经过查询缓冲提升查询速度;MySQL对查询的自动优化;基于索引的排序;不可达查询的检测和使用各类查询选择来提升性能。服务器

1、 经过查询缓冲提升查询速度性能

通常咱们使用SQL语句进行查询时,数据库服务器每次在收到客户端发来SQL后,都会执行这条SQL语句。但当在必定间隔内(如1分钟内),接到完 全同样的SQL语句,也一样执行它。虽然这样能够保证数据的实时性,但在大多数时候,数据并不要求彻底的实时,也就是说能够有必定的延时。若是是这样的话,在短期内执行彻底同样的SQL就有些得不偿失。测试

幸亏MySQL为咱们提供了查询缓冲的功能(只能在MySQL 4.0.1及以上版本使用查询缓冲)。咱们能够经过查询缓冲在必定程度上提升查询性能。优化

咱们能够经过在MySQL安装目录中的my.ini文件设置查询缓冲。设置也很是简单,只须要将query_cache_type设为1便可。在设 置了这个属性后,MySQL在执行任何SELECT语句以前,都会在它的缓冲区中查询是否在相同的SELECT语句被执行过,若是有,而且执行结果没有过 期,那么就直接取查询结果返回给客户端。但在写SQL语句时注意,MySQL的查询缓冲是区分大小写的。以下列的两条SELECT语句:设计

SELECT * from TABLE1 SELECT * FROM TABLE1排序

上面的两条SQL语句对于查询缓冲是彻底不一样的SELECT。并且查询缓冲并不自动处理空格,所以,在写SQL语句时,应尽可能减小空格的使用,尤为是在SQL首和尾的空格(由于,查询缓冲并不自动截取首尾空格)。索引

虽然不设置查询缓冲,有时可能带来性能上的损失,但有一些SQL语句须要实时地查询数据,或者并不常用(可能一天就执行一两次)。这样就须要把 缓冲关了。固然,这能够经过设置query_cache_type的值来关闭查询缓冲,但这就将查询缓冲永久地关闭了。在MySQL 5.0中提供了一种能够临时关闭查询缓冲的方法:开发

SELECT SQL_NO_CACHE field1, field2 FROM TABLE1table

以上的SQL语句因为使用了SQL_NO_CACHE,所以,无论这条SQL语句是否被执行过,服务器都不会在缓冲区中查找,每次都会执行它。

咱们还能够将my.ini中的query_cache_type设成2,这样只有在使用了SQL_CACHE后,才使用查询缓冲。

SELECT SQL_CALHE * FROM TABLE1

2、MySQL对查询的自动优化

索引对于数据库是很是重要的。在查询时能够经过索引来提升性能。但有时使用索引反而会下降性能。咱们能够看以下的SALES表:

CREATE TABLE SALES

( ID INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, NAME VARCHAR(100) NOT NULL,

PRICE FLOAT NOT NULL, SALE_COUNT INT NOT NULL,

SALE_DATE DATE NOT NULL,

PRIMARY KEY(ID),

INDEX (NAME),

INDEX (SALE_DATE) );

假设这个表中保存了数百万条数据,而咱们要查询商品号为1000的商品在2004年和2005年的平均价格。咱们能够写以下的SQL语句:
SELECT AVG(PRICE) FROM SALES

WHERE ID = 1000 AND SALE_DATE BETWEEN '2004-01-01' AND '2005-12-31';

若是这种商品的数量很是多,差很少占了SALES表的记录的50%或更多。那么使用SALE_DATE字段上索引来计算平均数就有些慢。由于若是使 用索引,就得对索引进行排序操做。当知足条件的记录很是多时(如占整个表的记录的50%或更多的比例),速度会变慢,这样还不如对整个表进行扫描。所以,MySQL会自动根据知足条件的数据占整个表的数据的比例自动决定是否使用索引进行查询。

对于MySQL来讲,上述的查询结果占整个表的记录的比例是30%左右时就不使用索引了,这个比例是MySQL的开发人员根据他们的经验得出的。然而,实际的比例值会根据所使用的数据库引擎不一样而不一样。

3、 基于索引的排序

MySQL的弱点之一是它的排序。虽然MySQL能够在1秒中查询大约15,000条记录,但因为MySQL在查询时最多只能使用一个索引。所以,若是WHERE条件已经占用了索引,那么在排序中就不使用索引了,这将大大下降查询的速度。咱们能够看看以下的SQL语句:

SELECT * FROM SALES WHERE NAME = “name” ORDER BY SALE_DATE DESC;

在以上的SQL的WHERE子句中已经使用了NAME字段上的索引,所以,在对SALE_DATE进行排序时将再也不使用索引。为了解决这个问题,咱们能够对SALES表创建复合索引:

ALTER TABLE SALES DROP INDEX NAME, ADD INDEX (NAME, SALE_DATE)

这样再使用上述的SELECT语句进行查询时速度就会大副提高。但要注意,在使用这个方法时,要确保WHERE子句中没有排序字段,在上例中就是不能用SALE_DATE进行查询,不然虽然排序快了,可是SALE_DATE字段上没有单独的索引,所以查询又会慢下来。

4、 不可达查询的检测

在执行SQL语句时,不免会遇到一些必假的条件。所谓必假的条件是不管表中的数据如何变化,这个条件都为假。如WHERE value < 100 AND value > 200。咱们永远没法找到一个既小于100又大于200的数。

若是遇到这样的查询条件,再去执行这样的SQL语句就是画蛇添足。幸亏MySQL能够自动检测这种状况。如咱们能够看看以下的SQL语句:

SELECT * FROM SALES WHERE NAME = “name1” AND NAME = “name2”

以上的查询语句要查找NAME既等于name1又等于name2的记录。很明显,这是一个不可达的查询,WHERE条件必定是假。MySQL在执行 SQL语句以前,会先分析WHERE条件是不是不可达的查询,若是是,就再也不执行这条SQL语句了。为了验证这一点。咱们首先对以下的SQL使用 EXPLAIN进行测试:

EXPLAIN SELECT * FROM SALES WHERE NAME = “name1”

上面的查询是一个正常的查询,咱们能够看到使用EXPLAIN返回的执行信息数据中table项是SALES。这说明MySQL对SALES进行操做了。再看看下面的语句:

EXPLAIN SELECT * FROM SALES WHERE NAME = “name1” AND NAME = “name2”

咱们能够看到,table项是空,这说明MySQL并无对SALES表进行操做。

5、 使用各类查询选择来提升性能

SELECT语句除了正常的使用外,MySQL还为咱们提供了不少能够加强查询性能的选项。如上面介绍的用于控制查询缓冲的SQL_NO_CACHE和SQL_CACHE就是其中两个选项。在这一部分,我将介绍几个经常使用的查询选项。

1. STRAIGHT_JOIN:强制链接顺序

当咱们将两个或多个表链接起来进行查询时,咱们并不用关心MySQL先连哪一个表,后连哪一个表。而这一切都是由MySQL内部经过一系列的计算、评估,最后得出的一个链接顺序决定的。以下列的SQL语句中,TABLE1和TABLE2并不必定是谁链接谁:

SELECT TABLE1.FIELD1, TABLE2.FIELD2 FROM TABLE1 ,TABLE2 WHERE …

若是开发人员须要人为地干预链接的顺序,就得使用STRAIGHT_JOIN关键字,以下列的SQL语句:

SELECT TABLE1.FIELD1, TABLE2.FIELD2 FROM TABLE1 STRAIGHT_JOIN TABLE2 WHERE …

由上面的SQL语句可知,经过STRAIGHT_JOIN强迫MySQL按TABLE一、TABLE2的顺序链接表。若是你认为按本身的顺序比MySQL推荐的顺序进行链接的效率高的话,就能够经过STRAIGHT_JOIN来肯定链接顺序。

2. 干预索引使用,提升性能

在上面已经提到了索引的使用。通常状况下,在查询时MySQL将本身决定是否使用索引,使用哪个索引。但在一些特殊状况下,咱们但愿MySQL只使用一个或几个索引,或者不但愿使用某个索引。这就须要使用MySQL的控制索引的一些查询选项。

限制使用索引的范围

有时咱们在数据表里创建了不少索引,当MySQL对索引进行选择时,这些索引都在考虑的范围内。但有时咱们但愿MySQL只考虑几个索引,而不是所有的索引,这就须要用到USE INDEX对查询语句进行设置。

SELECT * FROM TABLE1 USE INDEX (FIELD1, FIELD2) …

从以上SQL语句能够看出,不管在TABLE1中已经创建了多少个索引,MySQL在选择索引时,只考虑在FIELD1和FIELD2上创建的索引。

限制不使用索引的范围

若是咱们要考虑的索引不少,而不被使用的索引又不多时,可使用IGNORE INDEX进行反向选取。在上面的例子中是选择被考虑的索引,而使用IGNORE INDEX是选择不被考虑的索引。

SELECT * FROM TABLE1 IGNORE INDEX (FIELD1, FIELD2) …

在上面的SQL语句中,TABLE1表中只有FIELD1和FIELD2上的索引不被使用。

强迫使用某一个索引

上面的两个例子都是给MySQL提供一个选择,也就是说MySQL并不必定要使用这些索引。而有时咱们但愿MySQL必需要使用某一个索引(因为 MySQL在查询时只能使用一个索引,所以只能强迫MySQL使用一个索引)。这就须要使用FORCE INDEX来完成这个功能。

SELECT * FROM TABLE1 FORCE INDEX (FIELD1) …

以上的SQL语句只使用创建在FIELD1上的索引,而不使用其它字段上的索引。

3. 使用临时表提供查询性能

当咱们查询的结果集中的数据比较多时,能够经过SQL_BUFFER_RESULT.选项强制将结果集放到临时表中,这样就能够很快地释放MySQL的表锁(这样其它的SQL语句就能够对这些记录进行查询了),而且能够长时间地为客户端提供大记录集。

SELECT SQL_BUFFER_RESULT * FROM TABLE1 WHERE …

和SQL_BUFFER_RESULT.选项相似的还有SQL_BIG_RESULT,这个选项通常用于分组或DISTINCT关键字,这个选项通知MySQL,若是有必要,就将查询结果放到临时表中,甚至在临时表中进行排序。

SELECT SQL_BUFFER_RESULT FIELD1, COUNT(*) FROM TABLE1 GROUP BY FIELD1

6、 结论

在程序设计中一样存在一个“二八原则”,即20%的代码用去了80%的时间。数据库应用程序的开发亦然。数据库应用程序的优化,重点在于SQL的执行效率。而数据查询优化的重点,则是使得数据库服务器少从磁盘中读数据以及顺序读页而不是非顺序读页。

相关文章
相关标签/搜索