<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆 - 312, 文章 - 14, 評論 - 1393, 引用 - 0
    數據加載中……

    MySQL查詢的性能優化

    本文為原創,如需轉載,請注明作者和出處,謝謝!

    本文曾發表于IT168:http://tech.it168.com/o/2006-11-10/200611101025088.shtml

        查詢是數據庫技術中最常用的操作。查詢操作的過程比較簡單,首先從客戶端發出查詢的SQL語句,數據庫服務端在接收到由客戶端發來的SQL語句后,執行這 條SQL語句,然后將查詢到的結果返回給客戶端。雖然過程很簡單,但不同的查詢方式和數據庫設置,對查詢的性能將會有很在的影響。因此,本文就在 MySQL中常用的查詢優化技術進行討論。討論的內容如:

    1 通過查詢緩沖提高查詢速度
    2 MySQL對查詢的自動優化
    3 基于索引的排序
    4 不可達查詢的檢測
    5 使用各種查詢選擇來提高性能

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

        一 般我們使用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中提供了一種可以臨時關閉查詢緩沖的方法:SQL_NO_CACHE。   

    SELECT SQL_NO_CACHE field1, field2 FROM TABLE1

        以上的SQL語句由于使用了SQL_NO_CACHE,因此,不管這條SQL語句是否被執行過,服務器都不會在緩沖區中查找,每次都會執行它。 

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

    SELECT SQL_CALHE * FROM TABLE1

      二、MySQL對查詢的自動優化

        索引對于數據庫是非常重要的。在查詢時可以通過索引來提高性能。但有時使用索引反而會降低性能。我們可以看如下的SALES表:

    CREATE TABLE SALES
    (
      ID 
    INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
      NAME 
    VARCHAR(100NOT 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的開發人員根據他們的經驗得出的。然而,實際的比例值會根據所使用的數據庫引擎不同而不同。

    三、 基于索引的排序

        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字段上沒有單獨的索引,因此查詢又會慢下來。

    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表進行操作。

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

        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按TABLE1、TABLE2的順序連接表。如果你認為按自己的順序比MySQL推薦的順序進行連接的效率高的話,就可以通過STRAIGHT_JOIN來確定連接順序。

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

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

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

        有時我們在數據表里建立了很多索引,當MySQL對索引進行選擇時,這些索引都在考慮的范圍內。但有時我們希望MySQL只考慮幾個索引,而不是全部的索引,這就需要用到USE INDEX對查詢語句進行設置。

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

    從以上SQL語句可以看出,無論在TABLE1中已經建立了多少個索引,MySQL在選擇索引時,只考慮在FIELD1和FIELD2上建立的索引。

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

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

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

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

        (3) 強迫使用某一個索引

        上面的兩個例子都是給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

    六、 結論

        在程序設計中同樣存在一個“二八原則”,即20%的代碼用去了80%的時間。數據庫應用程序的開發亦然。數據庫應用程序的優化,重點在于SQL的執行效率。而數據查詢優化的重點,則是使得數據庫服務器少從磁盤中讀數據以及順序讀頁而不是非順序讀頁。





    Android開發完全講義(第2版)(本書版權已輸出到臺灣)

    http://product.dangdang.com/product.aspx?product_id=22741502



    Android高薪之路:Android程序員面試寶典 http://book.360buy.com/10970314.html


    新浪微博:http://t.sina.com.cn/androidguy   昵稱:李寧_Lining

    posted on 2008-05-24 08:54 銀河使者 閱讀(4227) 評論(2)  編輯  收藏 所屬分類: databases 、mysql 、 原創

    評論

    # re: MySQL查詢的性能優化  回復  更多評論   

    對于第二點“索引”的解釋有根據嗎?索引的優勢在于查詢,但是初始化費時。是否需要建索引應該根據表的更新頻率而定,表更新頻繁的用索引意義就不大了。

    如果索引不是表數據變化時(重新)建立的,而是按照你說的:每次查詢時建立。那么請問索引意義何在?
    2008-05-24 11:07 | stanleyxu

    # re: MySQL查詢的性能優化[未登錄]  回復  更多評論   

    mysql 5.0中的my.ini設置緩存好像是
    # Query cache is used to cache SELECT results and later return them
    # without actual executing the same query once again. Having the query
    # cache enabled may result in significant speed improvements, if your
    # have a lot of identical queries and rarely changing tables. See the
    # "Qcache_lowmem_prunes" status variable to check if the current value
    # is high enough for your load.
    # Note: In case your tables change very often or if your queries are
    # textually different every time, the query cache may result in a
    # slowdown instead of a performance improvement.
    query_cache_size=0
    2008-05-26 15:51 | zero
    主站蜘蛛池模板: 亚洲精品无码久久不卡| 色妞www精品视频免费看| 亚洲啪啪AV无码片| 日本免费一区二区三区最新| 最近中文字幕mv免费高清视频8 | 国产va免费精品观看精品| 中文在线观看永久免费| 国产亚洲一卡2卡3卡4卡新区| 亚洲精品白色在线发布| 国产成人亚洲精品青草天美| 亚洲不卡AV影片在线播放| 女人被男人躁的女爽免费视频| 亚洲精品国产免费| 国产精品免费AV片在线观看| 一级做α爱过程免费视频| 国产99久久亚洲综合精品| 亚洲人av高清无码| 亚洲精品第一综合99久久| 亚洲国产韩国一区二区| 自怕偷自怕亚洲精品| 亚洲国产精品线在线观看| 亚洲成A人片777777| 精品国产亚洲男女在线线电影| 亚洲AV蜜桃永久无码精品| 四虎永久成人免费| 国产一区二区免费在线| 宅男666在线永久免费观看| 青青草国产免费久久久下载| 成人免费无码大片a毛片软件| 我要看免费的毛片| 成人免费网站在线观看| 妞干网在线免费视频| 日本特黄特色aa大片免费| 国产又大又黑又粗免费视频| 免费又黄又爽又猛的毛片| 亚洲AⅤ视频一区二区三区| 亚洲另类激情专区小说图片| 国产亚洲美女精品久久久2020 | a免费毛片在线播放| XXX2高清在线观看免费视频| 中文字幕免费在线播放|