MySQL 普通索引和唯一索引的區別

来源:https://www.cnblogs.com/hhhhuanzi/archive/2020/02/16/12318504.html
-Advertisement-
Play Games

該文為《 MySQL 實戰 45 講》的學習筆記,感謝查看,如有錯誤,歡迎指正 一、查詢和更新上的區別 這兩類索引在查詢能力上是沒差別的,主要考慮的是對更新性能的影響。建議儘量選擇普通索引。 1.1 MySQL 的查詢操作 普通索引 查找到第一個滿足條件的記錄後,繼續向後遍歷,直到第一個不滿足條件的 ...


該文為《 MySQL 實戰 45 講》的學習筆記,感謝查看,如有錯誤,歡迎指正

一、查詢和更新上的區別

這兩類索引在查詢能力上是沒差別的,主要考慮的是對更新性能的影響。建議儘量選擇普通索引。

1.1 MySQL 的查詢操作
  • 普通索引
    查找到第一個滿足條件的記錄後,繼續向後遍歷,直到第一個不滿足條件的記錄。
  • 唯一索引
    由於索引定義了唯一性,查找到第一個滿足條件的記錄後,直接停止繼續檢索。

普通索引會多檢索一次,幾乎沒有影響。因為 InnoDB 的數據是按照數據頁為單位進行讀寫的,需要讀取數據時,並不是直接從磁碟讀取記錄,而是先把數據頁讀到記憶體,再去數據頁中檢索。

一個數據頁預設 16 KB,對於整型欄位,一個數據頁可以放近千個 key,除非要讀取的數據在數據頁的最後一條記錄,就需要再讀一個數據頁,這種情況很少,對CPU的消耗基本可以忽略了。

因此說,在查詢數據方面,普通索引和唯一索引沒差別。

1.2 MySQL 的更新操作

更新操作並不是直接對磁碟中的數據進行更新,是先把數據頁從磁碟讀入記憶體,再更新數據頁

  • 普通索引
    將數據頁從磁碟讀入記憶體,更新數據頁。
  • 唯一索引
    將數據頁從磁碟讀入記憶體,判斷是否唯一,再更新數據頁。

由於 MySQL 中有個 change buffer 的機制,會導致普通索引唯一索引在更新上有一定的區別。

change buffer的作用是為了降低IO 操作,避免系統負載過高。change buffer將數據寫入數據頁的過程,叫做merge

如果需要更新的數據頁在記憶體中時,會直接更新數據頁;如果數據不在記憶體中,會先將更新操作記入change buffer,當下一次讀取數據頁時,順帶merge到數據頁中,change buffer也有定期merge策略。資料庫正常關閉的過程中,也會觸發merge

對於唯一索引,更新前需要判斷數據是否唯一(不能和表中數據重覆),如果數據頁在記憶體中,就可以直接判斷並且更新,如果不在記憶體中,就需要去磁碟中讀出來,判斷一下是否唯一,是的話就更新。change buffer是用不到的。即使數據頁不在記憶體中,還是要讀出來。

change buffer 用的是 buffer pool 里的記憶體,因此不能無限增大。change buffer 的大小,可以通過參數 innodb_change_buffer_max_size 來動態設置。這個參數設置為 50 的時候,表示 change buffer 的大小最多只能占用 buffer pool 的 50%。

結論:唯一索引用不了change buffer,只有普通索引可以用。


二、change buffer 和 redo log的區別
2.1 change buffer 的適用場景

change buffer 的作用是降低更新操作的頻率,緩存更新操作。這樣會有一個缺點,就是更新不及時,對於讀操作比較頻繁的表,不建議使用 change buffer。

因為更新操作剛記錄進change buffer中,就讀取了該表,數據頁被讀到了記憶體中,數據馬上就merge到數據頁中了。這樣不僅不會降低性能消耗,反而會增加維護change buffer的成本。

適用於寫多讀少的表。


2.2 change buffer 和 redo log 區別

我們舉一個例子用來理解 redo logchange buffer。我們執行以下 SQL 語句:

mysql> insert into t(id,k) values(id1,k1),(id2,k2);

假設,(id1,k1) 在數據頁 Page 1 中,(id2,k2) 在數據頁 Page 2 中。並且 Page 1 在記憶體中,Page 2 不在記憶體中。

執行過程如下:

  1. 直接向 Page 1 中寫入 (id1,k1)
  2. change buffer 中記下"向 Page 2 中寫入(id2,k2)"這條信息;
  3. 將以上兩個動作記入redo log。

做完上面這些,事務就可以完成了。執行這條更新語句的成本很低,就是寫了兩處記憶體,然後寫了一處磁碟(兩次操作合在一起寫了一次磁碟),而且還是順序寫的。

這條更新語句,涉及了四個部分:記憶體、redo log(ib_log_fileX)、 數據表空間(t.ibd)、系統表空間(ibdata1)。
在這裡插入圖片描述
如果要讀數據的話,過程是怎樣的?

mysql> select * from t where k in (k1, k2);

假設讀操作在更新後不久,此時記憶體中還有 Page 1,沒有 Page 2,那麼讀操作就和 redo log 以及 ibdata1 無關了。

  1. 從記憶體中獲取到 Page 1 上的最新數據 (id1,k1)
  2. 將數據頁 Page 2 讀入記憶體,執行merge 操作,此時記憶體中的 Page 2 也有最新數據(id2,k2)
    在這裡插入圖片描述

需要註意的是:

  1. redo log中的數據,可能還沒有 flush 到磁碟,磁碟中的 Page 1 和 Page 2 中並沒有最新數據,但我們依然可以拿到最新數據(記憶體中的 Page 1 就是最新的,Page 2 雖然不是最新的,但是從磁碟讀到記憶體中後,執行了merge操作,記憶體中的 Page 2 就是最新的了。)
  2. 如果此時 MySQL 異常宕機了,比如伺服器異常掉電,change buffer 中的數據會不會丟?

    change buffer 中的數據分為兩部分,一部分是已經mergeibdata1中的數據,這部分數據已經持久化,不會丟失。另一部分數據,還在 change buffer 中,沒有mergeibdata1,分 3 種情況:

    (1)change buffer 寫入數據到記憶體,redo log 也已經寫入(ib-log-filex),但是未 commit,binlog中也沒有fsync到磁碟,這部分數據會丟失;
    (2)change buffer 寫入數據到記憶體,redo log 也已經寫入(ib-log-filex),但是未 commit,binlog 已寫入到磁碟,這部分不會多丟失,異常重啟後會先從 binlog 恢復 redo log,再從 redo log 恢復 change buffer;
    (3)change buffer 寫入數據到記憶體,redo log 和 binlog 都已經fsync,直接從redo log 恢復,不會丟失。

redo log 主要節省的是隨機寫磁碟的 IO 消耗(轉成順序寫),而 change buffer 主要節省的則是隨機讀磁碟的 IO 消耗


感謝閱讀,有興趣的小伙伴可以關註我的微信公眾號DevOps探索之旅,大家一起學習進步


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

-Advertisement-
Play Games
更多相關文章
  • 一、環境 VMWare+Centos7 二、寫在前面的話 安裝GCC最簡單的方式當然是【yum -y install gcc】但是我的機器上安裝下來後,其版本是4.8.5,感覺有點低,所以想升級一下(7.2.0, 8.2.0之類的版本)。於是需要手動安裝。 三、吃過的坑 1. 本地沒有GCC導致編譯 ...
  • rpm可以實現程式的快速,簡單安裝(跟編譯安裝比),但是rpm自己不能解決依賴,所以很多工具為了自動解決依賴應運而生,其中yum就是其中之一。 yum解決依賴的辦法: 必須有個文件伺服器,裡面放置所以的rpm包,以及包的相關元數據( qi, qR得到的數據)。元數據可以使用 來創建。並放置在repo ...
  • 1 DHCP伺服器簡介 DHCP(Dynamic Host Configuration Protocol),動態主機配置協議,DHCP 協議主要是用來自動為區域網中的客戶機分配TCP/IP 信息的網路協議,並完成每台客戶機的TCP/IP 協議配置。當我們將區域網中客戶機IP地址設置為動態獲取方式時, ...
  • 實驗環境:centos7 註:因為本次實驗在同一臺伺服器上,Apache與Nginx同為80埠,所以改Apache埠為60 1 配置Nginx伺服器: 編輯Nginx配置文件,寫入以下內容 location ~ \.php$ { 所有以.php結尾的文件,前面\代表轉義 proxy_pass h ...
  • 很多人都有寫博客的習慣,奈何國內的博客網站正在一家家地關閉與重整,部分博客網站也充斥著太多的廣告,使用體驗非常不好。對於愛寫博客的朋友來說,其實還有一個更好的選擇,那就是自己搭建一個博客。 ...
  • 前言 年過30惶惶不安,又逢疫情,還是不斷學習,強化自己的能力。hadoop的視頻和書籍在15年的時候就看過,但是一直沒動手實踐過,要知道技術不經過實戰,一點提升也沒有。因此下定決心邊學邊做,希望能有所收穫。 軟體版本介紹 virtualbox 6.1 centos7 hadoop 3.2.1 jd ...
  • 1 查詢指定欄位 在 employee 表找出所有員工的姓名、性別和電子郵箱。 SELECT 表示查詢,隨後列出需要返回的欄位,欄位間逗號分隔 FROM 表示要從哪個表中進行查詢 分號為語句結束符 這種查詢表中指定欄位的操作在關係運算中被稱為投影(Projection) 使用 SELECT 子句進行 ...
  • 1、概述 (1)鎖的定義 鎖是電腦協調多個進程或線程併發訪問某一資源的機制。 在資料庫中,除了傳統的計算資源(如CPU、RAM、IO等)的爭用以外,數據也是一種供需要用戶共用的資源。如何保證數據併發訪問的一致性、有效性是所有資料庫必須解決的一個問題,鎖衝突也是影響資料庫併發訪問性能的一個重要因素。 ...
一周排行
    -Advertisement-
    Play Games
  • 概述:在C#中,++i和i++都是自增運算符,其中++i先增加值再返回,而i++先返回值再增加。應用場景根據需求選擇,首碼適合先增後用,尾碼適合先用後增。詳細示例提供清晰的代碼演示這兩者的操作時機和實際應用。 在C#中,++i 和 i++ 都是自增運算符,但它們在操作上有細微的差異,主要體現在操作的 ...
  • 上次發佈了:Taurus.MVC 性能壓力測試(ap 壓測 和 linux 下wrk 壓測):.NET Core 版本,今天計劃準備壓測一下 .NET 版本,來測試並記錄一下 Taurus.MVC 框架在 .NET 版本的性能,以便後續持續優化改進。 為了方便對比,本文章的電腦環境和測試思路,儘量和... ...
  • .NET WebAPI作為一種構建RESTful服務的強大工具,為開發者提供了便捷的方式來定義、處理HTTP請求並返迴響應。在設計API介面時,正確地接收和解析客戶端發送的數據至關重要。.NET WebAPI提供了一系列特性,如[FromRoute]、[FromQuery]和[FromBody],用 ...
  • 原因:我之所以想做這個項目,是因為在之前查找關於C#/WPF相關資料時,我發現講解圖像濾鏡的資源非常稀缺。此外,我註意到許多現有的開源庫主要基於CPU進行圖像渲染。這種方式在處理大量圖像時,會導致CPU的渲染負擔過重。因此,我將在下文中介紹如何通過GPU渲染來有效實現圖像的各種濾鏡效果。 生成的效果 ...
  • 引言 上一章我們介紹了在xUnit單元測試中用xUnit.DependencyInject來使用依賴註入,上一章我們的Sample.Repository倉儲層有一個批量註入的介面沒有做單元測試,今天用這個示例來演示一下如何用Bogus創建模擬數據 ,和 EFCore 的種子數據生成 Bogus 的優 ...
  • 一、前言 在自己的項目中,涉及到實時心率曲線的繪製,項目上的曲線繪製,一般很難找到能直接用的第三方庫,而且有些還是定製化的功能,所以還是自己繪製比較方便。很多人一聽到自己畫就害怕,感覺很難,今天就分享一個完整的實時心率數據繪製心率曲線圖的例子;之前的博客也分享給DrawingVisual繪製曲線的方 ...
  • 如果你在自定義的 Main 方法中直接使用 App 類並啟動應用程式,但發現 App.xaml 中定義的資源沒有被正確載入,那麼問題可能在於如何正確配置 App.xaml 與你的 App 類的交互。 確保 App.xaml 文件中的 x:Class 屬性正確指向你的 App 類。這樣,當你創建 Ap ...
  • 一:背景 1. 講故事 上個月有個朋友在微信上找到我,說他們的軟體在客戶那邊隔幾天就要崩潰一次,一直都沒有找到原因,讓我幫忙看下怎麼回事,確實工控類的軟體環境複雜難搞,朋友手上有一個崩潰的dump,剛好丟給我來分析一下。 二:WinDbg分析 1. 程式為什麼會崩潰 windbg 有一個厲害之處在於 ...
  • 前言 .NET生態中有許多依賴註入容器。在大多數情況下,微軟提供的內置容器在易用性和性能方面都非常優秀。外加ASP.NET Core預設使用內置容器,使用很方便。 但是筆者在使用中一直有一個頭疼的問題:服務工廠無法提供請求的服務類型相關的信息。這在一般情況下並沒有影響,但是內置容器支持註冊開放泛型服 ...
  • 一、前言 在項目開發過程中,DataGrid是經常使用到的一個數據展示控制項,而通常表格的最後一列是作為操作列存在,比如會有編輯、刪除等功能按鈕。但WPF的原始DataGrid中,預設只支持固定左側列,這跟大家習慣性操作列放最後不符,今天就來介紹一種簡單的方式實現固定右側列。(這裡的實現方式參考的大佬 ...