慢查詢基礎:優化數據訪問

来源:https://www.cnblogs.com/AmosH/archive/2019/01/05/10225719.html
-Advertisement-
Play Games

查詢性能低下最基本的原因是訪問的數據太多。某些查詢不可避免的需要篩選大量數據,但這並不常見。大部分性能低下的查詢都可以通過減少訪問的數據量的方式進行優化 ...


查詢性能低下最基本的原因是訪問的數據太多。某些查詢不可避免的需要篩選大量數據,但這並不常見。大部分性能低下的查詢都可以通過減少訪問的數據量的方式進行優化

對於低效的查詢,可以通過下麵兩個步驟進行分析:

  1. 確認應用程式是否在檢索大量超過需要的數據。這通常意味著訪問了太多的行,但有時候也可能是訪問了太多的列
  2. 確認MySQL伺服器層是否在分析大量超過需要的數據行

是否向資料庫請求了不需要的數據

有些查詢會請求超過實際需要的數據,然後這些多餘的數據會被應用程式丟棄。這會給MySQL伺服器帶來額外的負擔,並增加網路開銷、應用伺服器的CPU以及記憶體資源。

讓我們來看一些典型案例:

查詢不需要的記錄

一個常見的錯誤就是人們會誤以為MySQL只會返回需要的數據,實際上MySQL確實先返回全部結果集然後再進行計算。

比如在新聞網站中取出100條記錄,但是只在頁面上顯示前10條。實際情況是MySQL會查詢出全部的結果集,客戶端的應用程式會在接收全部的結果集數據,然後拋棄其中大部分的數據。

解決這個問題最簡單有效的解決方案就是在這樣的查詢後面加上 LIMIT

總是取出所有列

每次看到SELECT * 都應該用懷疑的眼光審視,是不是真的需要返回全部的列?

答案很可能不是必須的。取出所有的列,會讓優化器無法完成索引覆蓋掃描這類的優化,還會為伺服器帶來額外的I/O、記憶體和CPU的消耗。因此,一些DBA是嚴格禁止這樣的寫法的,這樣做有時候還可以避免某些列被修改帶來的問題。

當然,查詢返回超過需要的數據也不總是壞事

使用這樣有點浪費資料庫資源的方式可以簡化開發,提高代碼片段的復用性。如果清楚這樣做的性能影響,那麼這種做法也是值得考慮的。

重覆查詢相同的數據

在編寫程式時有時候總會一不小心出現這樣的錯誤——不斷的重覆執行相同的查詢,然後每次都返回完全相同的數據。

比較好的方案是,當初次查詢的時候就應該把這個數據緩存起來,只有在需要的時候才從緩存中取出來,這樣子性能會更好。

MySQL是否在掃描額外的記錄

在確定查詢只返回需要的數據以後,接下來應該看看查詢為了返回結果是否掃描了過多的數據。

對於MySQL,最簡單的衡量查詢開銷的三個指標如下:

  • 響應時間
  • 掃描的行數
  • 返回的行數

沒有哪個指標可以完美的衡量查詢的開銷,但是他們大致反映了MySQL在內部執行查詢時需要訪問多少數據,並且可以大致推算出查詢運行的時間。這三個指標都會記錄到MySQL的慢日誌中,所以檢查慢日誌記錄是找出掃描行數過多的查詢的好辦法。

響應時間

響應時間是服務時間和排隊時間的和。服務時間指的是資料庫處理這個查詢真正花了多長時間。排隊時間指的是伺服器因為等待某些資源而沒有真正執行查詢的時間——可能等待I/O操作完成,也可能是等待行鎖等等。但是我們無法將響應時間細分到上面這些部分,所以響應時間既可能是一個問題的結果也可能是一個問題的原因。

當我們看到一個查詢的響應時間時,首先應該判斷這個響應時間是否是一個合理的值。概括來講,我們可以通過瞭解這個查詢需要那些索引以及它的執行計劃是什麼,然後計算大概需要多少個順序和隨機I/O,再乘以在具體硬體條件下一次I/O的消耗時間。最後把這些消耗加在一起,就可以獲得一個大概的參考值來判斷當前響應時間是不是一個合理的值。

掃描的行數與返回的行數

分析查詢時,查看該查詢掃描的行數是非常有幫助的。這在一定程度上能夠搜名該查詢查找數據的效率高不高。

但是這個指標可能還不夠完美,因為並不是所有的行的訪問代價都是相同的。較短的行的訪問速度更快,記憶體中的行也比磁碟中的行的訪問速度要快得多。

理想情況下掃描的行數以及返回的行數應該是相同的。

但實際上這樣完美的情況並不多見,比如在做關聯查詢時,伺服器需要掃描多行才能生成結果集中的一行。

掃描的行數和訪問類型

在評估查詢開銷時,需要考慮以下從表中找到某一行數據的成本。MySQL有好幾種訪問方式可以查找並返回一行結果。有些訪問方式可能需要掃描很多行才能返回一行結果,有些訪問方式可能無需掃描就能返回結果。

在EXPLAIN語句中的type列反映了訪問的類型。訪問類型有很多種,從全表掃描到索引掃描、範圍掃描、唯一索引查詢、常數引用等。這裡羅列的這些,速度從慢到快,掃描的行數也是從小到大。

如果查詢無法找到合適的訪問類型,那麼解決的最好辦法通常就是增加一個合適的索引。索引讓MySQL以最高效,掃描行數最少的方式找到需要的記錄。

我們看這樣一個例子:

SELECT * FROM sakila.file_actor WHERE file_id = 1;

這個查詢將會返回10行數據,從EXPLAIN的結果可以看到,MySQL在索引 idx_fk_film_id 上使用了ref訪問類型來執行查詢:

EXPLAIN的結果也顯示MySQL預估需要訪問10行數據。也就是說,查詢優化器認為這種訪問類型可以高效的完成查詢。

我們可以嘗試刪除索引,這樣MySQL就不得不使用更糟糕的訪問類型:

刪除索引之後,訪問類型變成了全表掃描。這裡的“Using Where”表示MySQL會通過WHERE條件來篩選存儲引擎返回的記錄。

一般MySQL能夠使用如下三種方式應用WHERE條件,從好到壞依次為:

  • 在索引中使用WHERE條件來過濾不匹配的記錄。這是在存儲引擎層完成的。
  • 使用索引覆蓋掃描(在Extra列會出現Using index)來返回記錄,直接從索引中過濾其他不需要的記錄並返回命中的結果。這是在MySQL伺服器層完成的。但是無需再回到表中查詢記錄。
  • 從數據表中返回數據,然後過濾不滿足條件的記錄(在Extra列中出現Using Where)。這在MySQL伺服器層完成,MySQL需要先從數據表讀出記錄然後過濾。

如果發現查詢需要掃描大量的數據但是只返回少數的行,那麼通常可以嘗試下麵的技巧去優化它:

  1. 使用索引覆蓋掃描,把所有需要用的列都放到索引中,這樣存儲引擎無需回表獲取對應的行就可以返回結果了。
  2. 改變庫表結構,比如說使用彙總表。
  3. 重寫這個複雜的查詢,讓MySQL優化器能夠以更優化的方式執行這個查詢

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • redis安裝 1. 安裝tcl cd /usr/local wget http://downloads.sourceforge.net/tcl/tcl8.6.1 src.tar.gz tar xzvf tcl8.6.1 src.tar.gz cd /usr/local/tcl8.6.1/unix/ ...
  • 一、學習文檔 官網網站: https://www.docker.com 中文網站:http://www.docker-cn.com 官方安裝文檔:https://docs.docker.com/install/linux/docker-ce/centos/ 最好的文檔和學習路勁,都是來自官方的一手資 ...
  • 一.概述 Zephyr支持在Windows、Linux和MacOS環境下開發,這裡只介紹如何在Windows下搭建zephyr的開發環境。 二.步驟 2.1安裝msys2 msys2是一個Linux模擬環境,類似於ArchLinux。 安裝完成後,要添加源(這與Linux環境是類似的),這裡我添加的 ...
  • Zephyr是一個面向物聯網的嵌入式實時操作系統(RTOS),是Linux基金會旗下的一個項目,具有以下特點: 1.安全的,靈活、高可擴展性,支持多種硬體平臺(ARM、ARC、X86、xtensa、nois2、riscv32); 2.基於Apache 2.0許可,完全開源,代碼托管在github; ...
  • Linux系統成功的關鍵因素之一就是具有與其他操作系統和諧共存的能力。Linux系統的文件系統由兩層結構構建:第一層是虛擬文件系統(VFS),第二層是各種不同的具體的文件系統。 VFS就是把各種具體的文件系統的公共部分抽取出來,形成一個抽象層,是系統內核的一部分,它位於用戶程式和具體的文件系統之間。 ...
  • 使用的centos版本為 7.5 首先我們要把jdk拷到linux中,這裡我們藉助XShell工具,我們先來看看Xshell的用法 打開Xshell 後點擊文件,“新建“,如下圖: 起一個名稱,主機填寫linux的的IP地址,打開終端 輸入 ifconfig即可查看ip地址 紅色箭頭指向的地方就是l ...
  • 本文所述MongoDB版本為4.0.5,筆者對MongoDB剛接觸,對各個版本的MongoDB不甚瞭解,本文不對該版本的MongoDB做特性介紹,所涉及命令也許對其餘版本不適用。 因為目前有一個試驗性的項目想要使用NoSQL,而MongoDB在工作中有一定的接觸,所以這個項目打算使用MongoDB ...
  • information_schema 此資料庫是MySQL資料庫自帶的,主要存儲資料庫的元數據,保存了關於MySQL伺服器維護的所有其他資料庫的信息,如資料庫名、資料庫表、表列的數據類型及訪問許可權等。 這個庫在很多情況下,可以幫助我們做一些自動化處理的工作,比如巡檢程式找到所有的MyISAM表,或者 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...