MySQL 資料庫表上做查詢慢的原因-愛可生

2020-12-08 愛可生雲資料庫

問題

26 問中,我們看到了如下 SQL 在 MySQL 5.7 中跑得很慢:

我們還分析了執行計劃改寫後的 SQL,通過猜測,增加了 hint 來解決問題:

這一期,我們通過工具來分析一下:MySQL 為什麼會使用一個低效的執行計劃,以致於我們不得已用 hint 來調優 SQL?

實驗

我們接著使用 26 問中的環境,使用 optimizer trace 工具,觀察 MySQL 對 SQL 的優化處理過程。

我們先調大 optimizer trace 的內存容量(否則 trace 的輸出會被截斷),然後開啟了optimizer trace 功能。

跑完 SQL 後,可以在 INFORMATION_SCHEMA.OPTIMIZER_TRACE 看到 SQL 的優化處理過程:

這會是個巨大的 json,我們將其複製出來,找個 json 的可視化編輯器來分析一下。

小貼士

如果 MySQL 啟動時有配置 --secure-file-priv,那可以用,

SELECT TRACE INTO DUMPFILE <filename> FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE;

將 trace 導出到文件裡,會更方便一些。

這裡我們選擇了一個在線的 json 編輯器,使用起來會方便一點:

可以看到整個優化過程分為 6 個步驟,前兩步都跟創建臨時表相關,然後是 join 的準備工作,再是兩步 join 優化,最後是 join 的執行。

回憶一下 26 問中,我們的子查詢應使用物化方式,但實際使用了 exists 子句方式,我們猜測這個選擇是在 join 的優化階段做出的。

仔細翻一翻,就會找到可疑的部分:

上圖中的中文,是從英文翻譯過來的。看上去我們找對了位置。

接下來我們逐步看看這個決策的依據是什麼:

顯然不物化的代價更小,那麼優化器選擇不物化是正確的選擇。

但使用 exists 子句進行子查詢的代價,顯然不可能為 0,MySQL 對這個代價的計算可能有誤。

我們得來看看 MySQL 是如何計算這個代價的:

執行 exists 子查詢的代價 = 執行一次子查詢的代價 * 子查詢需要執行的次數

顯然這個子查詢不可能只需要執行 0 次

這裡需要做一個額外的思考:在這個場景下,子查詢需要執行的次數,與父查詢的行數相同。

也就是紅框內需要執行的次數,取決於紅框外的 SQL 的結果集條數。

這裡 MySQL 將父表的結果集條數 稱為 "扇出度"(fanout)

顯然,這裡父表 information_schema.columns 的扇出度為 0,直接導致了優化器放棄了物化的策略

那 information_schema.columns 的扇出度為什麼是 0 呢?

查看 information_schema.tables 中對於 COLUMNS 表的描述,我們看到 MySQL 將 information_schema 中的元數據表做了特殊對待,其行數估計是沒有意義的。

到此我們找到了問題所在:MySQL 5.7 對元數據表使用了區別設計,與普通表的行數估算方式不同。

以後大家在 MySQL 5.7 中使用 information_schema 中的元數據表做複雜查詢時,需要額外注意執行計劃,可能需要使用 hint 指導優化器工作。

MySQL 8.0 中進行了數據字典的改造,information_schema 中的元數據表大部分都變成了視圖,其真實的數據源是 mysql 庫中的隱藏元數據表。

對 MySQL 8.0 的元數據表進行複雜查詢,執行計劃會比 MySQL 5.7 更加合理。

相關焦點

  • MySQL 優化案例 - select count-愛可生
    作者:xuty一、故事背景項目組聯繫我說是有一張 500w 左右的表做 select count(*)速度特別慢。,可以看到確實運行很慢,要 40 多秒左右,確實很不正常~mysql> select count(*) from api_runtime_log;++| count(*) |++| 5718952 |++1 row in set (42.95 sec)我們再去看下表結構,看上去貌似也挺正常的~存在主鍵,表引擎也是 InnoDB,字符集也沒問題。
  • MySQL 表上做查詢慢出現狀況-愛可生
    問題我們有一個 SQL,用於找到沒有主鍵 /唯一鍵的表,但是在 MySQL 5.7 上運行特別慢,怎麼辦?寫個簡單的腳本,製造一批帶主鍵和不帶主鍵的表:執行一下腳本:現在執行以下 SQL 看看效果:執行了 16.80s,感覺是非常慢了。
  • MySQL 表如何計算統計信息-愛可生
    本篇介紹 MySQL 表如何計算統計信息。表統計信息是資料庫基於成本的優化器最重要的參考信息;統計信息不準確,優化器可能給出不夠優化的執行計劃或者是錯誤的執行計劃。
  • mysql 慢查詢命令
    如何查找MySQL中查詢慢的SQL語句更多如何在mysql查找效率慢的SQL語句呢?下面介紹MySQL中如何查詢慢的SQL語句一、MySQL資料庫有幾個配置選項可以幫助我們及時捕獲低效SQL語句1,slow_query_log這個參數設置為ON,可以捕獲執行時間超過一定數值的SQL語句。
  • MySQL 數據校驗工具-愛可生
    其原理是在主庫執行基於 statement 的 SQL 語句來生成主庫數據塊的checksum,把相同的 SQL 語句傳遞到從庫執行,並在從庫上計算相同數據塊的 checksum,最後,比較主從庫上相同數據塊的 checksum 值,由此判斷主從數據是否一致。它能在非常大的表上工作的一個原因是,它把每個表分成行塊,並檢查每個塊與單個替換。選擇查詢。它改變塊的大小,使校驗和查詢在所需的時間內運行。
  • 詳解MySQL|MySQL中間件DBLE-第五章 後端資料庫相關特性-愛可生
    本期推送的內容為DBLE的高級特性:後端資料庫的相關特性。本節提綱本節內容是對後端的資料庫相關特性重點解析。後端資料庫的相關特性主要從讀寫分離、連接管理、上下文同步以及高可用故障切換四個方面拆分講解;讀寫分離與高可用故障切換是社區同學反饋中需求最大的部分,本節內容十分詳盡的講解了大家關注的關鍵技術點及相關處理細節,有助於增進對分布式應用的相關理解。
  • MySQL中InnoDB-Cluster 日常運維掃盲-愛可生
    作者:楊濤濤 資深資料庫專家,專研 MySQL 十餘年。擅長 MySQL、PostgreSQL、MongoDB 等開源資料庫相關的備份恢復、SQL 調優、監控運維、高可用架構設計等。目前任職於愛可生,為各大運營商及銀行金融企業提供 MySQL 相關技術支持、MySQL 相關課程培訓等工作。
  • mysql查詢資料庫導致中文亂碼
    mysql查詢資料庫,如果資料庫裡的欄位的值是中文,就會出現亂碼,怎麼解決呢?看下面的講解寫一個test.php的文檔,代碼如下所示,打開mysql的界面,新建一個xml的資料庫,再建一個student的數據表,欄位值和記錄如下圖所示,打開谷歌瀏覽器,運行test.php文檔。運行結果是下圖:看到了吧,出現亂碼了,怎麼辦呢?
  • 生產MySQL資料庫執行一次analyze採集信息,應用炸了
    MySQL資料庫看了一下執行計劃,發現執行計劃不正確,第一反應就是其中的一個表的統計信息不準確,導致了SQL語句的執行計劃不對,從高效的查詢SQL變成了慢SQL。mysql> analyze table t_test_1;session3:模擬執行analyze命令之後,在t_test_1表上執行一次select查詢
  • 考前複習必備MySQL資料庫(關係型資料庫管理系統)
    初學基礎連接MySQL,格式:mysql -h 主機地址 -u 用戶名 -p 用戶密碼連接到本機上的MySQL,首先打開DOS窗口,進入目錄mysqlbin,輸入mysql -uroot -p,回車後提示你輸密碼。連接遠程主機上的MySQL,遠程主機的IP,和用戶名root,密碼。
  • 「MySQL系列」分析Sql執行時間及查詢執行計劃(附資料庫和一千萬數據)
    大批量數據導入數據a 將資料庫導入伺服器中(如果是windows系統,這步省略)b 創建一個資料庫創建資料庫(db2),表tb_skuc 命令行登錄資料庫mysql -u 用戶名2.2.1 設置慢查詢日誌1.
  • MySQL裡快速找到 binlog 中是否有大事務-愛可生
    實驗 我們先創建個資料庫: 下面附上本期命令的文字版: ~/opt/mysql/5.7.20/bin/mysqlbinlog data/mysql-bin.000001 | grep "GTID$(printf '\t')last_committed" -B 1 \ | grep -E
  • PHP資料庫編程之MySQL優化策略概述
    2、如果我們們經對資料庫中的數據行進行增刪,那麼會出現數據ID過大的情況,用ALTER TABLE tablename AUTO_INCREMENT=N,使自增ID從N開始計數。3、對int類型添加 ZEROFILL 屬性可以對數據進行自動補04、導入大量數據時最好先刪除索引再插入數據,再加入索引,不然,mysql會花費大量時間在更新索引上。
  • 從Web查詢資料庫之PHP與MySQL篇
    腳本主要包括了連接資料庫和執行查詢的命令。PHP啟動了對MySQL伺服器的連接並向該伺服器發送適當的查詢。 MySQL伺服器接收到資料庫查詢的請求,開始處理這個查詢,並將查詢結果返回給PHP引擎。 PHP引擎完成了腳本的運行後,將該HTML返回Web伺服器。 Web伺服器再將HTML返回給客戶端瀏覽器,用戶就可以看到響應後的結果頁面。
  • MySQL優化:定位慢查詢的兩種方法以及使用explain分析SQL
    一條SQL查詢語句在經過MySQL查詢優化器處理後會生成一個所謂的執行計劃,這個執行計劃展示了具體執行查詢的方式,比如多表連接的順序是什麼,對於每個表採用什麼訪問方法來具體執行查詢等等。本章的內容就是為了幫助大家看懂EXPLAIN語句的各個輸出項都是幹嘛使的,從而可以有針對性的提升我們查詢語句的性能。
  • MySQL資料庫及應用
    查詢答案: A7 單選 資料庫、資料庫管理和資料庫系統之間的關係正確的是A. 資料庫包括了資料庫管理系統和資料庫系統B. 資料庫管理系統包括了資料庫和資料庫系統C.4 單選 PHP連接資料庫伺服器成功後,使用以下哪個函數執行SQL語句A. mysql_queryB. mysql_select_dbC. mysql_connectD. mysql_fetch_array
  • Mysql資料庫的使用方法
    7)它是一個可靠地事務處理引擎,不支持全文本搜索 (2) MyISAM引擎:        1)不支持每次查詢具有原子性        2)只支持表所        3)強調的是性能,其執行速度比InnoDB類型更快,但是不提供事務支持        4)如果執行大量的SELECT(刪除任務),MyISAM是更好的選擇2、資料庫的介紹
  • 「資料庫分享」MySQL資料庫優化
    查看慢查詢日誌相關配置mysql> show variables like 'slow_query%';修改全局慢查詢日誌配置。mysql> set global slow_query_log='ON';mysql> set global long_query_time=1;或者直接修改MySQL配置文件啟用慢查詢日誌。
  • 如何使用MySQL資料庫
    MySQL資料庫的數據文件存放在/usr/local/mysql/data目錄下,每個資料庫對應一個子目錄,用於存儲數據表文件。每個數據表對應三個文件,擴展名分別為「.frm」、「.myd」和「.myi」。(這裡就不細說了)3)查看表的結構「describe語句」:用於顯示錶的結構,即組成表的各欄位(列)的信息。
  • mysql分表的3種方法
    分表的目的就在於此,減小資料庫的負擔,縮短查詢時間。如果數據太多,一次執行的時間太長,等待的時間就越長,這也是我們為什麼要分表的原因。二,分表1,做mysql集群。例如:利用mysql cluster ,mysql proxy,mysql replication,drdb等等有人會問mysql集群,和分表有什麼關係嗎?雖然它不是實際意義上的分表,但是它起到了分表的作用。做集群的意義是什麼呢?為一個資料庫減輕負擔,說白了就是減少sql排隊隊列中的sql的數量。