結合數據索引結構看SQL的真實執行過程

引言

關于數據庫設計與優化的前幾篇文章中,我們提到了數據庫設計優化應該遵守的指導原則、數據庫底層的索引組織結構、數據庫的核心功能組件以及SQL的解析、編譯等。這些其實都是在為SQL的優化、執行的理解打基礎。
今天這篇文章,我們以MySQL中InnoDB存儲引擎中的數據索引組織及一條SQL的物理執行過程,來更直觀的理解數據庫中我們提交一條SQL后,數據庫默默幫我們做的事情。

準備工作

我們依然以前一篇文章中的t_customer表為例,建表語句如下:

create table t_customer(id int not null auto_increment comment '會員id',name varchar(32) comment '會員姓名',gender tinyint not null default 0 comment '會員性別:0未知,1男,2女',city varchar(32) comment '會員所在城市',primary key(`id`),key `idx_city` (`city`)
) comment '會員信息表';

然后我們編寫一個Python腳本,利用Faker框架,來生成測試數據:

import random
from faker import Faker
from faker.providers import BaseProvider
import pymysql
import db_config as db_cfgprint(db_cfg.host)conn = pymysql.connect(host=db_cfg.host, port=db_cfg.port, user=db_cfg.user, password=db_cfg.password,database=db_cfg.database)
cursor = conn.cursor()
sql = "insert into t_customer(name, gender, city) values('{}', {}, '{}')"class GenderProvider(BaseProvider):def gender(self):return random.sample([1, 2, 0], counts=[100, 100, 1], k=1)[0]# 指定語言環境為中文環境,創建Faker生成器
fk = Faker('zh_CN')
fk.add_provider(GenderProvider)
for i in range(10000):cursor.execute(sql.format(fk.name(), fk.gender(), fk.city()))
conn.commit()
cursor.close()
conn.close()

測試數據大概如下:

其實這里我們只是從數據組織結構上展開SQL的執行,沒有測試數據也沒啥影響。不過,還是強烈建議感興趣的了解下Python,很好用,很好玩。這里不再展開,需要理解的可以看下筆者關于Python的相關系列文章。

B+樹的索引組織結構

簡單說下B+樹索引

B+樹索引,就是傳統意義上的索引,也是目前關系型數據庫系統中查找最為常用和最有效的索引。
需要注意的是,從使用的角度來看,B+樹索引的構造類似于二叉樹,根據鍵值(key value)能夠快速找到相應的數據。但是,有幾個細節需要提一下:

  • B+樹中的B不是表示二叉(binary),而是代表平衡(balance),因為B+樹是從最早的平衡二叉樹演化而來的,但是B+樹不是一個二叉樹
  • 樹結構的索引,只有是平衡樹,才能降低樹的高度,從而降低基于索引檢索的磁盤IO的次數
  • B+樹索引,實際上并不能通過一個給定的鍵值查到具體的某一行數據,而是只能找到被查找符合鍵值的數據所在的頁,這些數據按照鍵值順序進行組織存儲。然后數據庫通過把頁讀入內存,然后在內存中執行進一步的查找操作,最終得到要查找的數據。后續我們簡化一下操作,假設每個頁都只存儲一條數據,以便更好地進行表述、理解
  • 關于數據以頁為單位進行讀取,前面的文章中已經提到,可以更好地利用程序的局部性原理,從而提高檢索的效率
t_customer的索引結構

引言中已經提到,我們這里以MySQL的InnoDB存儲引擎為例進行介紹,其他數據庫中的底層原理也基本類似。
從前面的建表語句中,可以看出t_customer有兩個索引:

  • 主鍵索引 id,是聚簇索引(Clustered Index)
  • idx_city,是輔助索引(Secondary Index)

索引的示意圖大概如下:

前面已經提到,我們簡化一下,一個頁只存儲一條數據。
輔助索引的葉子結點,存儲的都是該索引的鍵值及對應的主鍵的值;
聚簇索引的葉子節點,存儲的都是一行行完整的數據。

SQL執行過程

接下來,我們將要執行的是這樣一條SQL語句:

select id,name 
from t_customer 
where city = '合肥' and gender = 1

假設數據庫的優化器最終決定要走idx_city這個索引,進行SQL的執行,主要的執行過程大概如下:

  • 從索引idx_city中找到第一個滿足city = '合肥'的主鍵id;
  • 到主鍵id索引中取出整行,將id, name, gender取出,如果gender = 1 則將id, name的值放入內存緩沖區;
  • 重復前兩個步驟,直到在idx_city索引中找到的city值不滿足查詢條件為止
  • 將內存緩沖區的數據返回給用戶

上面的這條SQL,首先從idx_city索引中找到主鍵id,然后再到聚簇索引中找到整行記錄,然后還要判斷是否符合條件,再決定是否返回改行數據。這種查詢場景,叫做”回表“。
回表的操作,會增加磁盤IO的次數,如果輔助索引結構中已經包含了用戶需要的所有字段,則可以避免回表的操作,這時候的索引叫做”覆蓋索引“。

下面,我們對這條SQL稍微修改一下:

select id,name 
from t_customer 
where city = '合肥' and gender = 1
order byname 
limit 100

現在這條要執行的SQL中,添加了排序及limit操作,執行的過程會發生相應的調整,假設優化器還是選擇了要走idx_city這個索引:

  • 從索引idx_city中找到第一個滿足city = '合肥'的主鍵id;
  • 到主鍵id索引中取出整行,將id, name, gender取出,如果gender = 1 則將id, name的值放入排序緩沖區sor_buffer中;
  • 重復前兩個步驟,直到在idx_city索引中找到的city值不滿足查詢條件為止
  • 對sort_buffer中的數據按照字段name進行快速排序;
  • 按照排序結果的數據取出前100條,返回給用戶

其實,涉及到排序的話,問題會突然變得復雜起來,這里簡單描述下,可能的情況:
1、符合條件的行數很多,sort_buffer中放不下,這時候就不能直接基于內存的排序算法進行了,就需要我們前面文章提到的TPMMS的算法了,進行基于磁盤的多路歸并排序;
2、加入最終返回的字段比較多,執行引擎在執行的過程中,可能決定不將所有字段都放入sort_buffer,可能只放主鍵id和參與排序的字段,然后排序完成之后,需要再按序進行一次回表的操作,獲取用戶需要的所有字段,然后再返回給用戶。基于是否將所有字段放入sort_buffer中,排序的操作符可以簡單分為全字段排序和rowid排序。

實際上SQL的執行要考慮的真實場景比較復雜,本文為了便于描述與理解,做了相應的簡化,感興趣的可以自行研究。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/38465.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/38465.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/38465.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

vim卡死

有些時候使用vim的時候莫名其妙的會卡死,導致輸入不了內容。查了一下資料發現,其實并不是vim卡死,而是在使用vim的工程中帶入了許多Windows上的使用習慣,比如“Ctrl-s”保存等,這可能會與Linux平臺的有些快捷鍵沖突。c…

Oracle PL / SQL 表 table

關系數據庫允許您在數據庫管理系統(DBMS)中存儲多個表。 您可以使用計算機上的查詢語言來操作表中的數據。 當前的查詢語言是結構化查詢語言(SQL)。 SQL是一組無關的命令,用于操作關系數據庫管理系統(RD…

CleanMyMacX2024免費且強大的mac電腦系統優化工具

如果你的Mac電腦出現了存儲空間不足、運行緩慢、電池電量消耗過快等問題,那么CleanMyMacX這款軟件或許能為你提供解決方案。作為一款強大的系統優化工具,它能夠幫助用戶清理垃圾文件、優化內存和電池使用,從而提升Mac的性能表現,讓…

后端之路第三站(Mybatis)——XML文件操作sql

一、XML映射文件是啥 前面我們學過了在Mapper接口用注解的方式來操作sql語句 那么XML映射文件就另一種操作sql語句的方法 為什么還要有這么個玩意? 我簡單說就是:如果有的sql特別復雜的話,比如需要【動態sql】的話,就得用到XM…

【Android面試八股文】Fragment的add和replace的區別,分別對Fragment的生命周期有什么影響?

文章目錄 一、Fragment的add和replace的區別 ,分別對Fragment的生命周期有什么影響?1.1 `add` 方法1.2 `replace` 方法1.3 應用場景1.4 Fragment事務操作提交流程1.5 replace操作的本質是不是就是remove操作和add操作的組合?1.6 示例代碼:將一個已經存在的 `FragmentA` 替換…

電腦開機之后,鍵盤鼠標需要重新插拔才能正常使用?

前言 小白平時修電腦修得多,總是會遇到各種各樣的奇葩問題。這不,又有一位小伙伴來咨詢:電腦開機之后,鍵盤鼠標都不能用,需要重新插拔一下才能正常使用。 嘖嘖嘖,真的是很奇怪的問題,基本上沒見…

分頁緩存與下拉刷新的整合原理 - DoraPageDatabaseCacheRepository

何為分頁緩存? 顧名思義,分頁緩存就是邊分頁邊緩存,分頁通常使用下拉刷新控件實現,而緩存通常說的是指磁盤緩存,即保存到數據庫中,數據庫本身也是一個索引文件。 為什么緩存還要分頁? 在很大…

SSH 無密登錄配置流程

一、免密登錄原理 非對稱加密: 由于對稱加密的存在弊端,就產生了非對稱加密,非對稱加密中有兩個密鑰:公鑰和私鑰。公鑰由私鑰產生,但卻無法推算出私鑰;公鑰加密后的密文,只能通過對應的私鑰來解…

光速入門 Tailwind CSS

文章目錄 入門安裝IDE 設置使用預編譯器生產環境優化 基礎概念分層指令tailwindlayerapplyconfig 函數theme()screen() 基礎案例怎么設置屬性任意值?hover 父元素時,怎么選中子元素添加樣式?添加 animation 動畫 配置主題 Tailwind CSS 中文網…

.so: file not recognized: file format not recognized

項目場景: 自Linux 4.8起,傳統的GPIO sysfs接口被棄用。libgpiod操作gpio的方式感覺更加方便。 但是單板上好像沒裝這個工具,又到了熟悉的交叉編譯環節(痛苦)。 問題描述 按照流程裝完libgpiod,自信地去交…

安卓Gradle學習與應用:從入門到實踐

引言 在Android開發的世界里,Gradle不僅僅是一個構建工具,它更是一種強大的自動化系統,能夠幫助開發者高效地管理項目依賴、編譯、測試、打包以及部署。本篇博客旨在深入探討Gradle在Android開發中的應用,從基礎概念到實戰技巧&a…

334. 遞增的三元子序列

334. 遞增的三元子序列 題目鏈接&#xff1a;334. 遞增的三元子序列 代碼如下&#xff1a; class Solution { public://貪心bool increasingTriplet(vector<int>& nums) {if(nums.size()<3) {return false;}int firstnums[0],secondINT_MAX;for(int i1;i<…

Go源碼--context包

簡介 Context 是go語言比較重要的且也是比較復雜的一個結構體&#xff0c;Context主要有兩種功能: 取消信號&#xff1a;包括直接取消&#xff08;涉及的結構體&#xff1a;cancelCtx ; 涉及函數&#xff1a;WithCancel&#xff09;和攜帶截止日期的取消&#xff08;涉及結構…

密室逃脫——收集版

一、原版修改 1、導入資源 Unity Learn | 3D Beginner: Complete Project | URP 2、設置Scene 刪除SampleScene&#xff0c;打開UnityTechnologies-3DBeginnerComplete下的MainScene 3、降低音量 (1) 打開Hierarchy面板上的Audio降低音量 (2) 打開Prefabs文件夾&#xf…

Git安裝與使用及整合IDEA使用的詳細教程

1. 版本控制軟件介紹 版本控制軟件提供完備的版本管理功能&#xff0c;用于存儲、追蹤目錄&#xff08;文件夾&#xff09;和文件的修改歷史&#xff0c;是軟件開發者的必備工具&#xff0c;是軟件公司的基礎設施。版本控制軟件的最高目標&#xff0c;是支持軟件公司的配置管理…

第三天:LINK3D核心原理講解【第2部分】

三、 變量 // 點云容器 pcl::PointCloud<pcl::PointXYZI> laserCloud; // 一幀原始點云 pcl::PointCloud<pcl::PointXYZI> cornerPointsLessSharp; // 次極大邊線點 pcl::PointCloud<pcl::PointXYZI> surfPointsLessFlat; // 次極小平面點 pcl::PointCloud&…

ubuntu中后臺啟動一個jar

1.使用 nohup 和 & 啟動應用程序&#xff1a; nohup java -jar 你的jar包.jar > output.log 2>&1 &解釋&#xff1a; nohup&#xff1a;忽略掛起信號&#xff08;SIGHUP&#xff09;&#xff0c;使進程在退出終端后繼續運行。java -jar lxyoj-code-sandbox-…

管理統計學

第1章 統計學是收集、處理、分析、解釋數據并從數據中得出結論的科學。 統計學是處理數據的方法論。 參數 表示總體特征的概括性數字度量&#xff0c;是研究者想要了解的總體的某種特征值。 統計量 是用來描述樣本特征的概括性數字度量。 常用統計量包括&#xff1a; &#xff…

達夢數據庫系列—14. 表空間的備份和還原

目錄 1、表空間備份 2、表空間還原 3、表空間恢復 4、增量還原恢復 1、表空間備份 表空間只能在聯機狀態下進行備份。 BACKUP TABLESPACE TBS BACKUPSET /dm/backup/dm_bak/ts_bak_01; 完全備份 BACKUP TABLESPACE TBS FULL BACKUPSET /dm/backup/dm_bak/ts_full_bak_01…

ESP8266[ 關于-巴發云MQTT/TCP:arduino 設置回調函數 ] 日志2024/6/29

ESP8266 [ 關于-巴發云MQTT/TCP:arduino 設置回調函數 ] 日志2024/6/29 arduino庫:#include <PubSubClient.h> 回調函數 是其庫設置好的 可以改名字 這里只寫上關鍵代碼 設置客戶端為 A 關鍵代碼: A.setCallback(回調名) //MQTT 回調處理mqttmsgg(自定義…