`

通过force index了解的MySQL查询的性能优化

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

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

一、 通过查询缓冲提高查询速度

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

幸好MySQL为我们提供了查询缓冲的功能(只能在MySQL 4.0.1及以上版本使用查询缓冲)。我们可以通过查询缓冲在一定程度上提高查询性能。

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

1.SELECT * from TABLE1
2. 
3.SELECT * FROM TABLE1
上面的两条SQL语句对于查询缓冲是完全不同的SELECT。而且查询缓冲并不自动处理空格,因此,在写SQL语句时,应尽量减少空格的使用,尤其是在SQL首和尾的空格(因为,查询缓冲并不自动截取首尾空格)。

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

1.SELECT SQL_NO_CACHE field1, field2 FROM TABLE1
以上的SQL语句由于使用了SQL_NO_CACHE,因此,不管这条SQL语句是否被执行过,服务器都不会在缓冲区中查找,每次都会执行它。

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

1.SELECT SQL_CALHE * FROM TABLE1

二、MySQL对查询的自动优化

索引对于数据库是非常重要的。在查询时可以通过索引来提高性能。但有时使用索引反而会降低性能。我们可以看如下的SALES表:

1.CREATE TABLE SALES
2. 
3.(
4. 
5.ID INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
6. 
7.NAME VARCHAR(100) NOT NULL,
8. 
9.PRICE FLOAT NOT NULL,
10. 
11.SALE_COUNT INT NOT NULL,
12. 
13.SALE_DATE DATE NOT NULL,
14. 
15.PRIMARY KEY(ID),
16. 
17.INDEX (NAME),
18. 
19.INDEX (SALE_DATE)
20. 
21.);
假设这个表中保存了数百万条数据,而我们要查询商品号为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的开发人员根据他们的经验得出的。然而,实际的比例值会根据所使用的数据库引擎不同而不同。

三、 基于索引的排序

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

1.SELECT * FROM SALES WHERE NAME = “name” ORDER BY SALE_DATE DESC;
在以上的SQL的WHERE子句中已经使用了NAME字段上的索引,因此,在对SALE_DATE进行排序时将不再使用索引。为了解决这个问题,我们可以对SALES表建立复合索引:

1.ALTER TABLE SALES DROP INDEX NAME, ADD INDEX (NAME, SALE_DATE)
这样再使用上述的SELECT语句进行查询时速度就会大副提升。但要注意,在使用这个方法时,要确保WHERE子句中没有排序字段,在上例中就是不能用SALE_DATE进行查询,否则虽然排序快了,但是SALE_DATE字段上没有单独的索引,因此查询又会慢下来。

四、 不可达查询的检测

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

如果遇到这样的查询条件,再去执行这样的SQL语句就是多此一举。幸好MySQL可以自动检测这种情况。如我们可以看看如下的SQL语句:

1.SELECT * FROM SALES WHERE NAME = “name1” AND NAME = “name2”
以上的查询语句要查找NAME既等于name1又等于name2的记录。很明显,这是一个不可达的查询,WHERE条件一定是假。MySQL在执行 SQL语句之前,会先分析WHERE条件是否是不可达的查询,如果是,就不再执行这条SQL语句了。为了验证这一点。我们首先对如下的SQL使用 EXPLAIN进行测试:

1.EXPLAIN SELECT * FROM SALES WHERE NAME = “name1”
上面的查询是一个正常的查询,我们可以看到使用EXPLAIN返回的执行信息数据中table项是SALES。这说明MySQL对SALES进行操作了。再看看下面的语句:

1.EXPLAIN SELECT * FROM SALES WHERE NAME = “name1” AND NAME = “name2”
我们可以看到,table项是空,这说明MySQL并没有对SALES表进行操作。

五、 使用各种查询选择来提高性能

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

1. STRAIGHT_JOIN:强制连接顺序

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

1.SELECT TABLE1.FIELD1, TABLE2.FIELD2 FROM TABLE1 ,TABLE2 WHERE …
如果开发人员需要人为地干预连接的顺序,就得使用STRAIGHT_JOIN关键字,如下列的SQL语句:

1.SELECT TABLE1.FIELD1, TABLE2.FIELD2 FROM TABLE1 STRAIGHT_JOIN TABLE2 WHERE …
由上面的SQL语句可知,通过STRAIGHT_JOIN强迫MySQL按TABLE1、TABLE2的顺序连接表。如果你认为按自己的顺序比MySQL推荐的顺序进行连接的效率高的话,就可以通过STRAIGHT_JOIN来确定连接顺序。

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

在上面已经提到了索引的使用。一般情况下,在查询时MySQL将自己决定是否使用索引,使用哪一个索引。但在一些特殊情况下,我们希望MySQL只使用一个或几个索引,或者不希望使用某个索引。这就需要使用MySQL的控制索引的一些查询选项。

限制使用索引的范围

有时我们在数据表里建立了很多索引,当MySQL对索引进行选择时,这些索引都在考虑的范围内。但有时我们希望MySQL只考虑几个索引,而不是全部的索引,这就需要用到USE INDEX对查询语句进行设置。

1.SELECT * FROM TABLE1 USE INDEX (FIELD1, FIELD2) …
从以上SQL语句可以看出,无论在TABLE1中已经建立了多少个索引,MySQL在选择索引时,只考虑在FIELD1和FIELD2上建立的索引。

限制不使用索引的范围

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

1.SELECT * FROM TABLE1 IGNORE INDEX (FIELD1, FIELD2) …
在上面的SQL语句中,TABLE1表中只有FIELD1和FIELD2上的索引不被使用。

强迫使用某一个索引

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

1.SELECT * FROM TABLE1 FORCE INDEX (FIELD1) …
以上的SQL语句只使用建立在FIELD1上的索引,而不使用其它字段上的索引。

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

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

1.SELECT SQL_BUFFER_RESULT * FROM TABLE1 WHERE …
和SQL_BUFFER_RESULT.选项类似的还有SQL_BIG_RESULT,这个选项一般用于分组或DISTINCT关键字,这个选项通知MySQL,如果有必要,就将查询结果放到临时表中,甚至在临时表中进行排序。

1.SELECT SQL_BUFFER_RESULT FIELD1, COUNT(*) FROM TABLE1 GROUP BY FIELD1
六、 结论

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

分享到:
评论

相关推荐

    mysql查询优化之索引优化

    - **使用索引提示**:在某些复杂查询中,可以使用SQL的FORCE INDEX或USE INDEX提示强制MySQL使用特定的索引。 - **避免全表扫描**:通过优化查询语句,减少不必要的全表扫描,例如,避免在WHERE子句中使用NOT IN、!...

    运用解析器优化MySQL数据库查询性能.pdf

    MySQL数据库的查询性能优化是数据库管理员的关键任务,而索引是这一过程中不可或缺的工具。本文主要探讨了如何通过解析器优化MySQL的查询性能,重点介绍了几种利用索引进行优化的技术。 首先,索引在数据库查询优化...

    mysql的sql优化

    MySQL的SQL优化是数据库管理中的重要环节,尤其对于有经验的开发者来说,了解并掌握这一技能可以显著提升数据库性能,减少资源消耗。SQL优化主要涉及查询效率、索引使用、查询语句结构优化等多个方面。 首先,理解...

    MySql优化.pdf

    MySQL优化 MySQL优化是数据库管理中的一个重要...总结而言,MySQL优化是一个涉及多个层面的复杂过程,需要综合考虑配置、索引、查询语句、服务器状态等多方面因素,通过合理配置和优化,以达到提升数据库性能的目的。

    04-VIP-Mysql索引优化实战一.pdf

    通过在`SELECT`语句中添加`FORCE INDEX`子句,可以指定使用`idx_name_age_position`索引,即使查询条件包含`name`字段的范围查询。然而,强制使用索引并不总是提高查询性能,因为回表操作可能导致更多的I/O操作,...

    MySQL OCP超详细学习笔记.pdf

    本笔记涵盖了 MySQL 的多个方面,包括 MySQL 的配置、性能优化、索引管理、事务处理等。 首先,本笔记从 MySQL 的基本配置开始,介绍了 master-data 的配置、mysql key_buffer_size 的设置、Slave_IO_Running 和 ...

    mysql中or是否走索引详解

    如果你知道某个特定的索引应该被用于`OR`查询,可以使用`FORCE INDEX`或`INDEX`查询提示来强制优化器使用它。但这应谨慎使用,因为优化器通常是正确的,人工干预可能适得其反。 8. **更新统计信息** 保持统计信息...

    mysql索引分析和优化

    - **利用索引提示**:在复杂的查询中,可以使用`FORCE INDEX`、`USE INDEX`等提示强制数据库使用特定的索引,以优化查询计划。 #### 结论 理解MySQL索引的原理及其不同类型,结合具体的应用场景,合理设计和优化...

    MySQL SQL执行计划分析与优化.pdf

    在这种情况下,可以通过添加索引、调整查询语句或者使用`FORCE INDEX`来指导优化器。 7. **范围查找(range)与全表扫描(all)** - `range`查询使用索引来查找一个范围内的行,而`all`则表示没有使用索引,对所有行...

    MySQL VS ORACLE.pdf

    对于查询优化,Oracle提供了丰富的提示(hints)来指导优化器,而MySQL使用force index/use index来优化查询。Oracle的查询缓存能够存储SQL语句的执行结果,而MySQL的查询缓存功能较弱,通常只能在存储过程中使用。 ...

    mysql大数据查询优化经验分享(推荐)

    MySQL大数据查询优化是数据库性能提升的关键,特别是在处理海量数据时,高效的查询能够显著减少等待时间,提高用户体验。本文将分享一些实用的SQL优化技巧,主要关注索引优化和WHERE条件优化。 首先,对于大数据量...

    MySQL进阶学习需要掌握的具体内容解析,MySQL数据库如何使用和优化索引.docx

    ### MySQL进阶学习需要掌握的具体内容解析,MySQL数据库如何使用和...通过深入学习以上内容,您不仅能够更加熟练地操作MySQL数据库,还能在实际项目中有效提高数据库的性能和稳定性,从而更好地应对复杂的应用场景。

    记一次因线上mysql优化器误判引起慢查询事件

    本文讲述了线上MySQL数据库中由于优化器误判索引选择导致的慢查询事件,并分享了如何通过强制指定索引来解决此问题。这个案例涉及到了MySQL的查询优化器、索引选择机制、以及慢查询优化方面的知识。 1. MySQL优化器...

    MySQL OCP超详细学习笔记

    `Forceindex`可以强制MySQL使用指定的索引。 #### 9. MySQL权限相关 在MySQL中,`sql SECURITY DEFINER`和`INVOKER`用于指定存储过程、函数、触发器和视图的安全上下文。 #### 10. MySQL性能分析 `performance_...

    数据库优化

    例如,通过在查询语句前添加`EXPLAIN`关键字,可以分析SQL执行计划,了解其执行效率,包括哪些索引被使用、是否存在全表扫描等问题。对于需要大量数据的查询,使用`LIMIT`来限制返回结果的数量,可以避免不必要的...

    分析一个MySQL的异常查询的案例

    案例进一步使用force index来强制MySQL优化器使用特定索引,从而验证不同索引选择对查询性能的影响。通过这种方法,发现在某些情况下,优化器并没有选择最优索引,导致了不合理的查询计划。这可能是因为MySQL优化器...

    MYSQL基础知识,一些常用问题

    - **FORCE INDEX**: 使用`FORCE INDEX`关键字可以强制MySQL使用特定的索引来执行查询。 **2. 覆盖索引** - **覆盖索引**: 如果查询所需的所有列都在同一个索引中,那么这个索引就称为“覆盖索引”,这种情况下可以...

    22MySQL有哪些“饮鸩止渴”提高性能的方法?.pptx

    - **SQL语句优化**:使用`force index`强制使用特定索引,查询重写,以及设置合适的`long_query_time`以记录慢查询。 3. **QPS突增应对**: - **业务高峰**:当业务量激增,DBA可能需要删除不必要的业务,或限制...

    【表119,,促销计划执行表】 mysql 多表查询 执行计划.doc

    3. **使用FORCE INDEX**:强制MySQL使用特定的索引,忽略其他可能的优化选项。 4. **使用SQL_NO_CACHE**:排除缓存的影响,确保每次查询都从磁盘读取最新数据。 5. **使用DETERMINISTIC**:对于存储过程和函数,声明...

Global site tag (gtag.js) - Google Analytics