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的執行效率。而數據查詢優化的重點,則是使得數據庫服務器少從磁盤中讀數據以及順序讀頁而不是非順序讀頁。

相關文章
相關標籤/搜索