欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

分析一個MySQL的異常查詢的案例

 更新時間:2015年05月07日 09:48:49   投稿:goldensun  
這篇文章主要介紹了分析一個MySQL的異常查詢的案例,主要是針對索引方面的操作問題,需要的朋友可以參考下

問題

用戶工單疑問:相同的語句,只是最后的limit行數不同。奇怪的是,limit 10 的性能比limit 100的語句還慢約10倍。

隱藏用戶表信息,語句及結果如下

SELECT f1 , SUM(`f2`) `CNT` FROM T WHERE f1 IS NOT NULL AND f3 = '2014-05-12' GROUP BY f1 ORDER BY `CNT` DESC LIMIT 10;

執(zhí)行時間3 min 3.65 sec

SELECT f1 , SUM(`f2`) `CNT` FROM T WHERE f1 IS NOT NULL AND f3 = '2014-05-12' GROUP BY f1 ORDER BY `CNT` DESC LIMIT 100;

執(zhí)行時間1.24Sec.

性能差距非常大!

分析
MySQL Tips:追查語句執(zhí)行時最常用的方法,是通過explain來看語句的執(zhí)行計劃。 ?

更有沖擊性的效果是通過縮小范圍后,在這個數據下,limit 67和limit 68的執(zhí)行計劃相差很大。

兩個執(zhí)行計劃:

LIMIT 67
id: 1
select_type: SIMPLE
table: a
type: range
possible_keys: A,B,C
key: B
key_len: 387
ref: NULL
rows: 2555192
Extra: Using where; Using temporary; Using filesort
1 row in set (0.00 sec)

LIMIT 68
id: 1
select_type: SIMPLE
table: a
type: ref
possible_keys: A,B,C
key: A
key_len: 3
ref: const
rows: 67586
Extra: Using where; Using temporary; Using filesort
1 row in set (0.00 sec)

可以看到,兩個語句的執(zhí)行計劃不同:使用的索引不同。

MySQL Tips:explain的結果中,key表示最終使用的索引,rows表示使用這個索引需要掃描的行數,這是個估計值。

表中 索引A定義為 (f3, f4, f1, f2, f5); 索引B定義為(f1, f2, f3);

一個確認

雖然rows是估計值,但是指導索引使用的依據。既然limit 68能達到rows 67586,說明在第一個語句優(yōu)化器可選結果中,也應該有此值,為什么不會選擇索引A?
先確認一下我們上面的這個結論。

MySQL Tips:MySQL語法中能夠用force index 來強行要求優(yōu)化器使用某一個索引。

Explain SELECT f1 , SUM(f2) CNT FROM t force index(A) WHERE f1 IS NOT NULL AND f3 = ‘2014-05-12' GROUP BY P ORDER BY CNT DESC LIMIT 67\G

id: 1
select_type: SIMPLE
table: a
type: ref
possible_keys:A
key: A
key_len: 3
ref: const
rows: 67586
Extra: Using where; Using temporary; Using filesort
1 row in set (0.00 sec)

順便說明,由于我們指定了force index,因此優(yōu)化器不會考慮其他索引,possible_keys里只會顯示A。我們關注的是rows:67586。這說明在limit 67語句里,使用索引A也能夠減少行掃描。

MySQL Tips:MySQL優(yōu)化器會對possiable_key中的每個可能索引都計算查詢代價,選擇最小代價的查詢計劃。

至此我們大概可以猜測,這個應該是MySQL實現上的bug:沒有選擇合適的索引,導致使用了明顯錯誤的執(zhí)行計劃。

MySQL Tips:MySQL的優(yōu)化器執(zhí)行期間需要依賴于表的統計信息,而統計信息是估算值,因此有可能導致得到的執(zhí)行計劃非最優(yōu)。

但要說明的是,上述Tip是客觀情況造成(可接受),但本例卻是例外,因此優(yōu)化器實際上可以拿到能夠作出選擇正確結果的數據(rows值),但是最終選擇錯誤。

原因分析

MySQL優(yōu)化器是按照查詢代價的估算值,來確定要使用的索引。計算這個估算值的過程,基本是按照“估計需要掃描的行數”來確定的。

MySQL Tips:MySQL在目前集團主流使用的5.1和5.5版本中只能使用前綴索引。

因此,使用索引A只能用上字段f3,使用索引B只能用上字段f1。Rows即為使用了索引查到上下界,之后需要掃描的數據行數(估算值)。

上述的語句需要用到group和order by,因此執(zhí)行計劃中都有Using temporary; Using filesort。
流程上按順序先計算使用索引A的查詢代價。

之后依次計算其他possitabe_key的查詢代價。由于過程中需要排序,在得到一個暫定結果后,需要判斷是否有代價更低的排序方式(test_if_cheaper_ordering)。
與之前的大同小異,也是依靠估計掃描行數來計算代價。

在這個邏輯的實現過程中,存在一個bug:在估計當前索引的區(qū)分度的時候,沒有考慮到前綴索引。

即:假設表中有50w行數據,索引B(f1,f2,f3),則計算索引區(qū)分度時,需要根據能夠用上的前綴部分來確定。比如f1有1000個不同的值,則平均每個key值上的記錄數為500.如(f1,f2)有10000個同的值,則平均每個組合key上的記錄數為50,若(f1,f2,f3)有50w個不同的值,則平均每個組合key上的記錄數為1。

MySQL Tips:每個key上的記錄數越少,說明使用該索引查詢時效率最高。對應于show index from tbl 輸出結果中的Cardinality值越大。

在這個case下,索引B只能使用f1做前綴索引,但是在計算單key上的行平均值時用的是(f1,f2,f3),這就導致估算用索引B估算的時候,得到的代價偏小。導致誤選。

回到問題本身

1、 為什么limit值大的時候反而選對了呢?
這是因為在計算B的查詢代價時,查詢需要返回的行數limit_rows也參與乘積,若limit值較大,則計算出來的B的代價就會更大,反而會由于代價。值超過A,而導致優(yōu)化器最終選擇A。

2、 這個表有50w行數就,為什么limit相差為就差別這么大?
這與語句本身有關。這個語句中有group by,這就意味著每多l(xiāng)imit一個值,實際上需要掃描更多的行N。 這里N為“表的總行數”/“表中不同的f2值”。
也就是說這個語句使得這個bug有放大作用。

解決方案

分析清楚后解決方法就比較簡單了,修改代碼邏輯,在執(zhí)行test_if_cheaper_ordering過程中,改用字段f1的區(qū)分度來計算即可。

相關文章

  • mysql修改sql_mode報錯的解決

    mysql修改sql_mode報錯的解決

    今天在Navicat中運行sql語句創(chuàng)建數據表出現了錯誤Err 1067。本文主要介紹了mysql修改sql_mode報錯的解決,感興趣的可以了解一下
    2021-09-09
  • 企業(yè)生產MySQL優(yōu)化介紹

    企業(yè)生產MySQL優(yōu)化介紹

    這篇文章主要介紹了企業(yè)生產MySQL優(yōu)化介紹的相關內容,文中敘述了其優(yōu)化內容,各個方面介紹的比較詳細,需要的朋友可以參考。
    2017-10-10
  • Mysql中replace與replace into的用法講解

    Mysql中replace與replace into的用法講解

    今天小編就為大家分享一篇關于Mysql中replace與replace into的用法講解,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-03-03
  • MySQL數據庫命令

    MySQL數據庫命令

    這篇文章主要介紹了數據庫的常用命令,數據庫中對表的命令以及一些常用的數據庫查詢和常用函數,感興趣的小伙伴可以借鑒一下
    2023-03-03
  • 在MySQL中使用LIMIT進行分頁的方法

    在MySQL中使用LIMIT進行分頁的方法

    這篇文章主要介紹了在MySQL中使用LIMIT進行分頁的方法,作者列舉出了三種方法,并且針對跳頁等常見問題做出了提示,需要的朋友可以參考下
    2015-05-05
  • DBeaver連接mysql數據庫錯誤圖文解決方案

    DBeaver連接mysql數據庫錯誤圖文解決方案

    這篇文章主要給大家介紹了關于DBeaver連接mysql數據庫錯誤解決方案的相關資料,DBeaver是免費、開源、通用數據庫工具,是許多開發(fā)開發(fā)人員和數據庫管理員的所選,需要的朋友可以參考下
    2023-11-11
  • Mysql 本地計算機無法啟動 mysql 服務 錯誤 1067:進程意外終止。

    Mysql 本地計算機無法啟動 mysql 服務 錯誤 1067:進程意外終止。

    初學php接觸mysql,遇到一些問題,卸載重裝后,無法啟動mysql服務,網絡上有很多種說法,我這里將我解決這個問題的辦法提出
    2009-12-12
  • 最新MySQL高級SQL語句大全

    最新MySQL高級SQL語句大全

    這篇文章主要介紹了MySQL高級SQL語句,主要包括常用查詢知識order by按關鍵字排序的sql語句,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-06-06
  • CentOS Mysql數據庫如何實現定時備份

    CentOS Mysql數據庫如何實現定時備份

    這篇文章主要介紹了CentOS Mysql數據庫如何實現定時備份,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-06-06
  • MYSQL的索引使用注意小結

    MYSQL的索引使用注意小結

    這篇文章主要介紹了MYSQL的索引使用注意,本文通過示例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-09-09

最新評論