1. 程式人生 > >資料庫優化一般思路

資料庫優化一般思路

隨著系統規模的不斷增加,資料量和併發量不斷增大,整個系統架構中最先受到衝擊而形成瓶頸的,定然是資料庫,因此資料庫層面的優化,是一個程式設計師不可或缺的技能,以下是我在使用資料庫中的一些心得,有不足之處,還望批評指正完善。

        首先簡單介紹下sql執行的過程,如下圖

      當你在sql客戶端(如命令列或者navicat)提交一條sql後,sql解析引擎會被啟動,此時,sql引擎會去解析優化這條sql,比如有時候你發現你寫的sql 查詢條件中的資料型別雖然和資料庫表定義的資料型別不一致,但是還是能夠得到正確的執         行,是因為資料庫引擎幫你做了自動轉化,比如

       select * from user where telephone=13937147647   telephone為varchar型別

        雖然型別不一致,但是sql會得到正確執行,是因為資料庫引擎幫你做了自動型別轉化

        不僅如此,資料庫表定義了多個索引,你寫的sql可能都會命中,sql引擎會幫你選擇最優的一個,這些都是此階段完成的 

        接下來,資料庫引擎會拿著優化好的sql命令語義去硬碟中查詢資料,然後將查詢到的資料返回(如果此時返回的結果集過大,會造成資料庫IO繁忙,會大大損傷sql效率,所以一般我們都使用分頁的原因就在於此)

        我們熟悉了sql執行過程之後,開始瞭解各種優化方式吧:

        1、索引,建立索引是資料庫優化各種方案之中成本最低,見效最快的解決方案,一般來講,資料庫規模在幾十萬和幾百萬級別的時候見效最快,即便是有不太複雜的表關聯,也能大幅度提高sql的執行效率,這個在我們以前的專案應用中,有非常深刻的體會,本來耗時50s的sql,在增加索引後可以提升到1-2s,而且不需要有程式碼改動,成本低廉,見效明顯

         建立索引需要注意的地方

         a、索引一般加在查詢條件的關鍵字上,如果有多個查詢條件關鍵字,還可以新增組合索引,寫sql的時候需要注意,索引欄位和sql欄位需要保持一致,否則索引會無效,比如

              簡單粗暴一點兒,我直接使用我們主資料資料庫(測試庫)中的md_house_property_info表中的source_house_code_no欄位,這個欄位在資料庫中被定義為了varchar型別,定義了多個索引,都包含了source_house_code_no欄位

           大家看,source_house_code_no我寫成varchar型別的時候,是可以走索引的

         當我寫成數字的時候,sql能夠正確執行,但是卻沒有命中索引

         大家再細心一點兒會發現,我這裡面有個possiable_keys,這個是指的可能命中的索引,此處出現了兩個,但是資料庫引擎會選擇最優的一個idx_source_house_code_no,這個過程我在開始有介紹了

        b、不要在查詢=前面使用函式,否則會導致索引不生效,舉個栗子,where str=substring(“hello world”,6,8),這樣是可以走索引的,但是 where substring(str,6,8)=“hello world” 是不會命中索引的

        c、建立索引的欄位要區分度比較高,比如user表中有一個性別字段,性別欄位無非男女兩種值,區分度不好,建立索引效果不好,要選擇區分度高的欄位

        d、建立組合索引,可以持續提升sql執行效率,但是也不要盲目,同樣的要注意區分度,如果區分度不夠高,就不要加了,多個欄位,儘可能把區分度高的欄位放在前面,另外,還要注意索引長度,這個索引要同時兼顧索引長度和區分度的平衡

        e、索引會大幅提升查詢效率,但是也會損耗查詢後修改效率,要注意兼顧平衡,使用在一次插入,多次查詢的表上效果最好,同時要注意的是,組合索引會不可避免的增加索引長度,會增加索引儲存空間,注意索引長度和區分度平衡

        f、後來因為工作需要,意外發現mysql居然支援全文索引,沒測試過效率,正常使用全文索引都是使用 lunce,以及在其之上的solr和現在正火的elastisearch,後面可以單獨來說

        2、分庫分表分割槽

        分庫,可以按照業務分庫,分流資料庫併發壓力,使資料庫表更加有條理性,最起碼更加好找吧,我們當時是把查詢庫和系統庫(增刪改比較頻繁的表)分開了,這樣如果有大查詢,不影響系統庫

        分表,剛才說了,索引適合應對百萬級別的資料量,千萬級別資料量使用的好,勉強也能湊合,但如果是上億級別的資料量,索引就無能為力了,因為單索引檔案可能就已經上百兆或者更多了,那麼,輪到我們的分表分割槽登場了

        分表的方法有很多種

        a、如果這個業務是有流程的,那麼我們通常會設計一個歷史表或者歸檔表,用來存放歷史資料,這樣能保證實時資料效率比較高

        b、針對某一張大表,可以根據查詢條件分成多張表,比如時間,我們可以將半個月或者10天的資料放到一張表裡(看具體資料量,個人認為3000W是個上限,最好控制到百萬級別),每過10天,我們就自動建立一張資料庫表,然後將資料插入,如此,按照時間查詢,就要先定位去那種表中去取數,這樣,效率能夠得到大幅度提升,當然,這麼解決也有問題,比如跨表,需要union多張表,而且跨表沒法支援索引

         c、上面的方法是我們直接通過程式和資料庫實現的最原始的分表解決方案,現在市面上有一些成熟的軟體如mycat,也是支援分表的,我們之前從事的公司有個專門做分散式資料庫的,這些產品出現跨表,可以不使用程式union了,而且還是使索引生效,但是需要對產品有一定的掌握

         d、一般來講,資料庫中的大表畢竟只是一少部分,僅需要對這少部分大表進行分表就可以了,沒必要小表也進行分表,增加維護開發難度

        分割槽

        分割槽的實現道理和分表一樣,也是將相應規則的資料放在一起,唯一不同的是分割槽你只需要設定好分割槽規則,插入的資料會被自動插入到指定的區裡,當然查詢的時候也能很快查詢到需要區,相當於是分表對外透明瞭,出現跨表資料庫自動幫我們合併做了處理,使用起來比分表更加方便,但是分割槽也有自己的問題,每一個數據庫表的併發訪問是有上限的,也就是說,分表能夠抗高併發,而分割槽不能,如何選擇,要考慮實際情況

       3、資料庫引擎

            也是偶爾聽一個dba同事提到的,有一次我跟dba同事抱怨,我的資料庫查詢太慢,有沒有好的優化方法,他一開始就問,資料量多大,有沒有索引,使用的什麼資料庫引擎,這時我才意識到原來資料庫引擎也算是一種優化方案

            mysql比較常用的資料庫引擎有兩種,一種是innodb、一種是myisam 

            我當時做過一個千萬級資料量複雜sql測試,myisam的效率大概能夠比innodb快1-2倍,雖然效率提升不是很明顯,但是也有提升,後來查過一些資料,說之所以mysiam快,是因為他的資料儲存結構、索引儲存結構和innodb不一樣的,mysiam的索引結構是在記憶體中存的

            當然,mysiam也有弱點,那就是他是表級鎖,而innodb是行級鎖,所以,mysiam適用於一次插入,多次查詢的表,或者是讀寫分離中的讀庫中的表,而對於修改插入刪除操作比較頻繁的表,就很不合適了

       4、預處理

        一般來說,實時資料(當天的資料)還是比較有限的,真正資料量比較大的是歷史資料,基於大表歷史資料的查詢,如果再涉及一些大表關聯,這種sql是非常難以優化的

       a、實時資料(當天資料)

            通過對對業務的抽象,可以放在快取裡面,提升系統執行效率

       b、歷史資料,大資料表歷史資料且有表關聯,通過常規sql難以優化,但是該資料通常有個共性,就是第二天去查詢前一天的資料做分析報表,也就是說對時效性要求不高,這種情況的解決方案是預處理

             做法是將這些複雜表關聯sql寫成個定時任務在半夜執行,將執行的結果存入到一張結果表中,第二天直接查詢結果表,如此,效率能得到十分明顯提升

       c、和b類似,可以將表關聯結果存入solr或者elastisearch中,以此提升效率,目前我們的專案就是如此處理

       5、mysql  like查詢

            大家都知道,like  “%str%” 不支援索引, "str%"號是支援索引的

            因此,如果業務允許,可以使用前匹配的方法是資料庫快速定位到資料,在結果集中再進行like匹配,如果這個結果集不是很大,是可以大幅提升執行效率的,這個需要對業務和程式有靈活的變通

            如果業務實在不允許前匹配,那就可以採用solr或者elastisearch來進行模糊匹配,但是進行模糊匹配有個前提,原始資料是字串的話,不要帶有特殊符號,如#,&,% 等,這樣會造成分詞不準,最終導致查詢結果不正確

      6、讀寫分離

           在資料庫併發大的情況下,最好的做法就是進行橫向擴充套件,增加機器,以提升抗併發能力,而且還兼有資料備份功能 ---------------------  作者:欣陽121  來源:CSDN  原文:https://blog.csdn.net/zhoupan301415/article/details/78257783  版權宣告:本文為博主原創文章,轉載請附上博文連結!