日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

MySQL查询的性能优化

發(fā)布時(shí)間:2024/4/11 数据库 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MySQL查询的性能优化 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
查詢是數(shù)據(jù)庫(kù)技術(shù)中最常用的操作。查詢操作的過程比較簡(jiǎn)單,首先從客戶端發(fā)出查詢的SQL語句,數(shù)據(jù)庫(kù)服務(wù)端在接收到由客戶端發(fā)來的SQL語句后,執(zhí)行這條SQL語句,然后將查詢到的結(jié)果返回給客戶端。雖然過程很簡(jiǎn)單,但不同的查詢方式和數(shù)據(jù)庫(kù)設(shè)置,對(duì)查詢的性能將會(huì)有很在的影響。因此,本文就在 MySQL中常用的查詢優(yōu)化技術(shù)進(jìn)行討論。討論的內(nèi)容如:

1 通過查詢緩沖提高查詢速度
2 MySQL對(duì)查詢的自動(dòng)優(yōu)化
3 基于索引的排序
4 不可達(dá)查詢的檢測(cè)
5 使用各種查詢選擇來提高性能

一、 通過查詢緩沖提高查詢速度?

??? 一般我們使用SQL語句進(jìn)行查詢時(shí),數(shù)據(jù)庫(kù)服務(wù)器每次在收到客戶端發(fā)來SQL后,都會(huì)執(zhí)行這條SQL語句。但當(dāng)在一定間隔內(nèi)(如1分鐘內(nèi)),接到完全一樣的 SQL語句,也同樣執(zhí)行它。雖然這樣可以保證數(shù)據(jù)的實(shí)時(shí)性,但在大多數(shù)時(shí)候,數(shù)據(jù)并不要求完全的實(shí)時(shí),也就是說可以有一定的延時(shí)。如果是這樣的話,在短時(shí)間內(nèi)執(zhí)行完全一樣的SQL就有些得不償失。?

??? 幸好MySQL為我們提供了查詢緩沖的功能(只能在MySQL 4.0.1及以上版本使用查詢緩沖)。我們可以通過查詢緩沖在一定程度上提高查詢性能。?

??? 我們可以通過在MySQL安裝目錄中的my.ini文件設(shè)置查詢緩沖。設(shè)置也非常簡(jiǎn)單,只需要將query_cache_type設(shè)為1即可。在設(shè)置了這個(gè)屬性后,MySQL在執(zhí)行任何SELECT語句之前,都會(huì)在它的緩沖區(qū)中查詢是否在相同的SELECT語句被執(zhí)行過,如果有,并且執(zhí)行結(jié)果沒有過期,那么就直接取查詢結(jié)果返回給客戶端。但在寫SQL語句時(shí)注意,MySQL的查詢緩沖是區(qū)分大小寫的。如下列的兩條SELECT語句:

SELECT?*?from?TABLE1
SELECT?*?FROM?TABLE1

??? 上面的兩條SQL語句對(duì)于查詢緩沖是完全不同的SELECT。而且查詢緩沖并不自動(dòng)處理空格,因此,在寫SQL語句時(shí),應(yīng)盡量減少空格的使用,尤其是在SQL首和尾的空格(因?yàn)?#xff0c;查詢緩沖并不自動(dòng)截取首尾空格)。?

??? 雖然不設(shè)置查詢緩沖,有時(shí)可能帶來性能上的損失,但有一些SQL語句需要實(shí)時(shí)地查詢數(shù)據(jù),或者并不經(jīng)常使用(可能一天就執(zhí)行一兩次)。這樣就需要把緩沖關(guān)了。當(dāng)然,這可以通過設(shè)置query_cache_type的值來關(guān)閉查詢緩沖,但這就將查詢緩沖永久地關(guān)閉了。在MySQL 5.0中提供了一種可以臨時(shí)關(guān)閉查詢緩沖的方法:SQL_NO_CACHE。???

SELECT?SQL_NO_CACHE?field1,?field2?FROM?TABLE1

??? 以上的SQL語句由于使用了SQL_NO_CACHE,因此,不管這條SQL語句是否被執(zhí)行過,服務(wù)器都不會(huì)在緩沖區(qū)中查找,每次都會(huì)執(zhí)行它。?

??? 我們還可以將my.ini中的query_cache_type設(shè)成2,這樣只有在使用了SQL_CACHE后,才使用查詢緩沖。

SELECT?SQL_CALHE?*?FROM?TABLE1

? 二、MySQL對(duì)查詢的自動(dòng)優(yōu)化

??? 索引對(duì)于數(shù)據(jù)庫(kù)是非常重要的。在查詢時(shí)可以通過索引來提高性能。但有時(shí)使用索引反而會(huì)降低性能。我們可以看如下的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)
)

?? 假設(shè)這個(gè)表中保存了數(shù)百萬條數(shù)據(jù),而我們要查詢商品號(hào)為1000的商品在2004年和2005年的平均價(jià)格。我們可以寫如下的SQL語句:

SELECT?AVG(PRICE)?FROM?SALES
WHERE?ID?=?1000?AND?SALE_DATE?BETWEEN?'2004-01-01'?AND?'2005-12-31';
??? 如果這種商品的數(shù)量非常多,差不多占了SALES表的記錄的50%或更多。那么使用SALE_DATE字段上索引來計(jì)算平均數(shù)就有些慢。因?yàn)槿绻褂盟饕?#xff0c;就得對(duì)索引進(jìn)行排序操作。當(dāng)滿足條件的記錄非常多時(shí)(如占整個(gè)表的記錄的50%或更多的比例),速度會(huì)變慢,這樣還不如對(duì)整個(gè)表進(jìn)行掃描。因此, MySQL會(huì)自動(dòng)根據(jù)滿足條件的數(shù)據(jù)占整個(gè)表的數(shù)據(jù)的比例自動(dòng)決定是否使用索引進(jìn)行查詢。

??? 對(duì)于MySQL來說,上述的查詢結(jié)果占整個(gè)表的記錄的比例是30%左右時(shí)就不使用索引了,這個(gè)比例是MySQL的開發(fā)人員根據(jù)他們的經(jīng)驗(yàn)得出的。然而,實(shí)際的比例值會(huì)根據(jù)所使用的數(shù)據(jù)庫(kù)引擎不同而不同。

三、 基于索引的排序

??? MySQL的弱點(diǎn)之一是它的排序。雖然MySQL可以在1秒中查詢大約15,000條記錄,但由于MySQL在查詢時(shí)最多只能使用一個(gè)索引。因此,如果 WHERE條件已經(jīng)占用了索引,那么在排序中就不使用索引了,這將大大降低查詢的速度。我們可以看看如下的SQL語句:

SELECT?*?FROM?SALES?WHERE?NAME?=?“name”?ORDER?BY?SALE_DATE?DESC;
??? 在以上的SQL的WHERE子句中已經(jīng)使用了NAME字段上的索引,因此,在對(duì)SALE_DATE進(jìn)行排序時(shí)將不再使用索引。為了解決這個(gè)問題,我們可以對(duì)SALES表建立復(fù)合索引:

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

??? 這樣再使用上述的SELECT語句進(jìn)行查詢時(shí)速度就會(huì)大副提升。但要注意,在使用這個(gè)方法時(shí),要確保WHERE子句中沒有排序字段,在上例中就是不能用 SALE_DATE進(jìn)行查詢,否則雖然排序快了,但是SALE_DATE字段上沒有單獨(dú)的索引,因此查詢又會(huì)慢下來。

SELECT?*?FROM?SALES?WHERE?NAME?=?“name1”?AND?NAME?=?“name2”
??? 以上的查詢語句要查找NAME既等于name1又等于name2的記錄。很明顯,這是一個(gè)不可達(dá)的查詢,WHERE條件一定是假。MySQL在執(zhí)行SQL 語句之前,會(huì)先分析WHERE條件是否是不可達(dá)的查詢,如果是,就不再執(zhí)行這條SQL語句了。為了驗(yàn)證這一點(diǎn)。我們首先對(duì)如下的SQL使用EXPLAIN 進(jìn)行測(cè)試:

EXPLAIN?SELECT?*?FROM?SALES?WHERE?NAME?=?“name1”
??? 上面的查詢是一個(gè)正常的查詢,我們可以看到使用EXPLAIN返回的執(zhí)行信息數(shù)據(jù)中table項(xiàng)是SALES。這說明MySQL對(duì)SALES進(jìn)行操作了。再看看下面的語句:

EXPLAIN?SELECT?*?FROM?SALES?WHERE?NAME?=?“name1”?AND?NAME?=?“name2”
?? 我們可以看到,table項(xiàng)是空,這說明MySQL并沒有對(duì)SALES表進(jìn)行操作。

五、 使用各種查詢選擇來提高性能?

??? SELECT語句除了正常的使用外,MySQL還為我們提供了很多可以增強(qiáng)查詢性能的選項(xiàng)。如上面介紹的用于控制查詢緩沖的SQL_NO_CACHE和SQL_CACHE就是其中兩個(gè)選項(xiàng)。在這一部分,我將介紹幾個(gè)常用的查詢選項(xiàng)。?

??? 1. STRAIGHT_JOIN:強(qiáng)制連接順序?

??? 當(dāng)我們將兩個(gè)或多個(gè)表連接起來進(jìn)行查詢時(shí),我們并不用關(guān)心MySQL先連哪個(gè)表,后連哪個(gè)表。而這一切都是由MySQL內(nèi)部通過一系列的計(jì)算、評(píng)估,最后得出的一個(gè)連接順序決定的。如下列的SQL語句中,TABLE1和TABLE2并不一定是誰連接誰:

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

??? 如果開發(fā)人員需要人為地干預(yù)連接的順序,就得使用STRAIGHT_JOIN關(guān)鍵字,如下列的SQL語句:

SELECT?TABLE1.FIELD1,?TABLE2.FIELD2?FROM?TABLE1?STRAIGHT_JOIN?TABLE2?WHERE?…
由上面的SQL語句可知,通過STRAIGHT_JOIN強(qiáng)迫MySQL按TABLE1、TABLE2的順序連接表。如果你認(rèn)為按自己的順序比MySQL推薦的順序進(jìn)行連接的效率高的話,就可以通過STRAIGHT_JOIN來確定連接順序。

??? 2. 干預(yù)索引使用,提高性能

??? 在上面已經(jīng)提到了索引的使用。一般情況下,在查詢時(shí)MySQL將自己決定是否使用索引,使用哪一個(gè)索引。但在一些特殊情況下,我們希望MySQL只使用一個(gè)或幾個(gè)索引,或者不希望使用某個(gè)索引。這就需要使用MySQL的控制索引的一些查詢選項(xiàng)。

?? (1) 限制使用索引的范圍

??? 有時(shí)我們?cè)跀?shù)據(jù)表里建立了很多索引,當(dāng)MySQL對(duì)索引進(jìn)行選擇時(shí),這些索引都在考慮的范圍內(nèi)。但有時(shí)我們希望MySQL只考慮幾個(gè)索引,而不是全部的索引,這就需要用到USE INDEX對(duì)查詢語句進(jìn)行設(shè)置。

SELECT?*?FROM?TABLE1?USE?INDEX?(FIELD1,?FIELD2)?…
從以上SQL語句可以看出,無論在TABLE1中已經(jīng)建立了多少個(gè)索引,MySQL在選擇索引時(shí),只考慮在FIELD1和FIELD2上建立的索引。

??? (2) 限制不使用索引的范圍

?? 如果我們要考慮的索引很多,而不被使用的索引又很少時(shí),可以使用IGNORE INDEX進(jìn)行反向選取。在上面的例子中是選擇被考慮的索引,而使用IGNORE INDEX是選擇不被考慮的索引。

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

??? (3) 強(qiáng)迫使用某一個(gè)索引

??? 上面的兩個(gè)例子都是給MySQL提供一個(gè)選擇,也就是說MySQL并不一定要使用這些索引。而有時(shí)我們希望MySQL必須要使用某一個(gè)索引(由于 MySQL在查詢時(shí)只能使用一個(gè)索引,因此只能強(qiáng)迫MySQL使用一個(gè)索引)。這就需要使用FORCE INDEX來完成這個(gè)功能。

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

??? 3. 使用臨時(shí)表提供查詢性能

??? 當(dāng)我們查詢的結(jié)果集中的數(shù)據(jù)比較多時(shí),可以通過SQL_BUFFER_RESULT.選項(xiàng)強(qiáng)制將結(jié)果集放到臨時(shí)表中,這樣就可以很快地釋放MySQL的表鎖(這樣其它的SQL語句就可以對(duì)這些記錄進(jìn)行查詢了),并且可以長(zhǎng)時(shí)間地為客戶端提供大記錄集。

??SELECT?SQL_BUFFER_RESULT?*?FROM?TABLE1?WHERE?…

??? 和SQL_BUFFER_RESULT.選項(xiàng)類似的還有SQL_BIG_RESULT,這個(gè)選項(xiàng)一般用于分組或DISTINCT關(guān)鍵字,這個(gè)選項(xiàng)通知MySQL,如果有必要,就將查詢結(jié)果放到臨時(shí)表中,甚至在臨時(shí)表中進(jìn)行排序。

SELECT?SQL_BUFFER_RESULT?FIELD1,?COUNT(*)?FROM?TABLE1?GROUP?BY?FIELD1
六、 結(jié)論

??? 在程序設(shè)計(jì)中同樣存在一個(gè)“二八原則”,即20%的代碼用去了80%的時(shí)間。數(shù)據(jù)庫(kù)應(yīng)用程序的開發(fā)亦然。數(shù)據(jù)庫(kù)應(yīng)用程序的優(yōu)化,重點(diǎn)在于SQL的執(zhí)行效率。而數(shù)據(jù)查詢優(yōu)化的重點(diǎn),則是使得數(shù)據(jù)庫(kù)服務(wù)器少?gòu)拇疟P中讀數(shù)據(jù)以及順序讀頁而不是非順序讀頁。 《銀河系列原創(chuàng)教程》發(fā)布 《Java Web開發(fā)速學(xué)寶典》出版,歡迎定購(gòu)

總結(jié)

以上是生活随笔為你收集整理的MySQL查询的性能优化的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。