1. 程式人生 > >SQL 優化第一彈

SQL 優化第一彈

rim spf 原因 exists 重新 5% 分享 掃描 lin

由於最近公司的sql 總是總是超時,所以進行sql 的優化

原s‘q‘l :

SELECT
        temp.*,tcc.customer_level customerLevel
        FROM
        (
        SELECT
        id_car idCar,
        id_customer idCustomer,
        c.brand_id brandId,
        c.factory_id factoryId,
        c.series_id seriesId,
        c.year_id yearId,
        main_id mainId,
        NAME,
        sex,
        customer_source customerSource,
        customer_type customerType,
        company_name companyName,
        cell_phone cellPhone,
        birthday,
        car_no carNo,
        car_prefix carPrefix,
        vin,
        factory_year factoryYear,
        car_model carModel,
        car_model_short carModelShort,
        cm.id_own_org idOwnOrg,
        cm.creationtime,
        cm.creator,
        cm.modifier,
        cm.modifiedtime,
        m.points,
        m. 
LEVEL, c.car_type AS carType, c.car_category_id AS carCategoryId FROM tm_customer_car cm INNER JOIN tm_customer m ON cm.id_customer = m.pk_id AND m.is_del = 0 INNER JOIN tm_car c ON cm.id_car = c.pk_id AND c.is_del = 0 WHERE cm.id_own_org
in ( CAST(10545511425563138989 as unsigned ) , CAST(10545511425563140093 as unsigned ) , CAST(10545511425563140621 as unsigned ) , CAST(10545511425563141565 as unsigned ) ,
CAST(10545511425563139362 as unsigned ) , CAST(10545511425563136430 as unsigned ) , CAST(10545511425563138387 as unsigned ) , CAST(10545511425563137867 as unsigned ) , CAST(10545511425563139144 as unsigned ) , CAST(10545511425563139602 as unsigned ) , CAST(10545511425563128134 as unsigned ) , CAST(10545511425563140397 as unsigned ) , CAST(10545511425563137692 as unsigned ) , CAST(10545511425563140988 as unsigned ) , CAST(10545511425563138546 as unsigned ) , CAST(10545511425563139830 as unsigned ) , CAST(10545511425563136673 as unsigned ) , CAST(10545511425563138073 as unsigned ) , CAST(10545511425563137152 as unsigned ) , CAST(10545511425563138802 as unsigned ) , CAST(10545511425563137450 as unsigned ) , CAST(10545511425563135631 as unsigned ) , CAST(10545511425563136936 as unsigned ) ) and c.car_type = 0 and CONCAT_WS("",m.name,m.mnemonic,m.cell_Phone,c.car_prefix,c.car_no,c.contact_name,c.contact_cellphone,c.vin) like "%"28B0X"%" ORDER BY cm.id_customer DESC Limit 0, 10 ) AS temp LEFT JOIN tm_customer_config tcc ON temp. LEVEL = tcc.pk_id;

執行計劃:

對表c 進行了全表查詢是導致sql 的根本原因;

其實在表中已經對其中的列加了索引,但因為的最優選擇而沒使用,同一個sql 在本地和生產的服務器上的執行計劃是不一樣的,這也驗證了我下面的結論;

我嘗試了各種方法:

tm_customer_car   id_customer,id_own_org 都已經有索引;
給 tm_car car_type列加索引意義不大;  列的值唯一性太小 --》放棄;

而給like 裏的字段加索引,因為這邊用的是 ‘%like%’ , 不會使用索引–》放棄;

對 tm_customer tm_car 選進行is_del 的select ,查詢時間沒怎麽變化--》放棄。

最總在我們架構師的提醒下發現其實只要將where 的提交提前查詢就好了,這樣就可以使用已經建立的索引;

技術分享

優化後的執行計劃

  INNER JOIN tm_car c ON cm.id_car = c.pk_id
        AND c.is_del = 0
        AND c.id_own_org IN (
            CAST(
                10545511425563138989 AS UNSIGNED
            ),
            CAST(
                10545511425563140093 AS UNSIGNED
            ),
            CAST(
                10545511425563140621 AS UNSIGNED
            ),
            CAST(
                10545511425563141565 AS UNSIGNED
            ),
            CAST(
                10545511425563139362 AS UNSIGNED
            ),
            CAST(
                10545511425563136430 AS UNSIGNED
            ),
            CAST(
                10545511425563138387 AS UNSIGNED
            ),
            CAST(
                10545511425563137867 AS UNSIGNED
            ),
            CAST(
                10545511425563139144 AS UNSIGNED
            ),
            CAST(
                10545511425563139602 AS UNSIGNED
            ),
            CAST(
                10545511425563128134 AS UNSIGNED
            ),
            CAST(
                10545511425563140397 AS UNSIGNED
            ),
            CAST(
                10545511425563137692 AS UNSIGNED
            ),
            CAST(
                10545511425563140988 AS UNSIGNED
            ),
            CAST(
                10545511425563138546 AS UNSIGNED
            ),
            CAST(
                10545511425563139830 AS UNSIGNED
            ),
            CAST(
                10545511425563136673 AS UNSIGNED
            ),
            CAST(
                10545511425563138073 AS UNSIGNED
            ),
            CAST(
                10545511425563137152 AS UNSIGNED
            ),
            CAST(
                10545511425563138802 AS UNSIGNED
            ),
            CAST(
                10545511425563137450 AS UNSIGNED
            ),
            CAST(
                10545511425563135631 AS UNSIGNED
            ),
            CAST(
                10545511425563136936 AS UNSIGNED
            )
        )
        AND c.car_type = 0

技術分享

總結:

1.執行計劃不一致問題:

同一個SQL語句 會由於表的數據(量、和值個數不同等)變化而執行不同的執行計劃,因為隨著表的數據(量、和值個數不同等)變化,執行同一個執行計劃的代價也在變化。

同一個SQL語句 選擇 一個執行計劃的依據:

表 統計信息 由此計算出 不同的執行計劃的代價 由此選代價小的執行計劃

表 的統計信息 一定要反映表當前的數據情況,否則選出的執行計劃實際上不是代價最小那個,此時就要優化了,重新更新下表 的統計信息;

2.執行計劃的解讀

id select_type table type extra

sql從裏向外執行,通過以上觀察發現

sql是按照id從大到小執行的。

1)、SIMPLE(不使用UNION或子查詢等)

2) 、PRIMARY:最外層的select

3)、DERIVED:派生表的SELECT(FROM子句的子查詢)

4)、UNION:UNION中的第二個或後面的SELECT語句

5)、UNION RESULT:UNION的結果。

6)、DEPENDENT UNION:UNION中的第二個或後面的SELECT語句,取決於外面的查詢

7)、SUBQUERY:子查詢中的第一個SELECT

8)、DEPENDENT SUBQUERY:子查詢中的第一個SELECT,取決於外面的查詢

有時不是真實的表名字,

看到的是derivedx(x是個數字,我的理解是第幾步執行的結果)

效率最高的是system,然後依次是

const、eq_ref、ref、range、index和 All。

一般來說,得保證查詢至少達到range級別,

最好能達到ref,否則就可能會出現性能問題。

Using filesort 看到這個的時候,查詢就需要優化了。MYSQL需要進行額外的步驟來發現如何對返回的行排序。它根據連接類型以及存儲排序鍵值和匹配條件的全部行的行指針來排序全部行 Using index 列數據是從僅僅使用了索引中的信息而沒有讀取實際的行動的表返回的,這發生在對表的全部的請求列都是同一個索引的部分的時候 Using temporary 看到這個的時候,查詢需要優化了。這裏,MYSQL需要創建一個臨時表來存儲結果,這通常發生在對不同的列集進行ORDER BY上,而不是GROUP BY上

參考:

常見的優化方式:

  1. 查詢條件減少使用函數,避免全表掃描
  2. 減少不必要的表連接
  3. 有些數據操作的業務邏輯可以放到應用層進行實現
  4. 可以使用with as
  5. 使用“臨時表”暫存中間結果
  6. 不要把SQL語句寫得太復雜
  7. 不能循環執行查詢
  8. 用 exists 代替 in
  9. 表關聯關系不要太糾結
  10. 查詢多用索引列取查,用charindex或者like[0-9]來代替%%
  11. inner關聯的表可以先查出來,再去關聯leftjoin的表
  12. 可以進行表關聯數據拆分,即先查出核心數據,再通過核心數據查其他數據,這樣會快得多
  13. 參考SQL執行順序進行優化
  14. 表關聯時取別名,也能提高效率
  15. 使用視圖,給視圖建立索引進行優化
  16. 使用數據倉庫的形式,建立單獨的表存儲數據,根據時間戳定期更新數據。將多表關聯的數據集中抽取存入一張表中,查詢時單表查詢,提高了查詢效率。

SQL 優化第一彈