1. 程式人生 > >如何成為建資料庫索引的高手?資料庫進階

如何成為建資料庫索引的高手?資料庫進階

今天來聊聊資料庫裡的索引,你知道的,網上這樣的文章一抓一大把的, 基本都是從索引的原理說起,講到索引的分類, 物理組織和儲存形式,如何找到對應的記錄,如何構建複雜的索引等等 ,如果我再寫一篇這樣的就沒意思了,而且這些未必真的是大家(尤其是開發同學)關心的。所以我今天打算以一個不同的角度來講下索引,而且針對B+tree索引,希望大家看了會有所幫助。

對於一個SQL,開發同學最關心的啥? 我覺得並不是這個SQL在資料庫裡面是如何執行的,而是這條SQL是否能儘快的返回結果,前面我們在講連線池的時候提到過,在SQL的生命週期裡,每一個環節都有足夠的優化空間,但是我們有沒有想過,SQL優化的本質是啥?終極目標又是啥?其實優化本質上就是減少SQL對資源的消耗和依賴,正如資料庫優化的終極大招是Do nothing in database一樣,SQL優化的終極目的也是Consume no resource。

資源有兩個特性:首先資源是有限的,大家都搶著用就會有瓶頸的,所以SQL的瓶頸可能是由資源緊張產生的。其次資源是有代價的,並且代價各異,比如記憶體的時延100ns, SSD100us,SAS盤10ms,網路更高,那麼訪問CPU l1/l2/l3 cache的代價就比訪問記憶體的要低,訪問記憶體資源的代價要比訪問硬碟資源的代價低,所以SQL的瓶頸也可能是訪問了代價比較高的資源導致的。現代計算機體系下,機器上粗粒度的資源就那麼幾種,無非就是CPU,記憶體,硬碟,和網路。那麼我們來看下SQL需要消耗哪些資源:比較、排序、SQL解析、函式或邏輯運算需要用到CPU;快取資料訪問,臨時資料存放需要用到記憶體;冷資料讀取,大資料量的排序和關聯,資料寫入落盤,需要訪問硬碟;SQL請求互動,結果集返回需要網路資源。那麼我們在資料庫裡面對SQL的優化思路,自然是減少SQL的解析,減少複雜的運算,減少資料處理的規模,減少對物理IO的依賴,減少伺服器和客戶端的網路互動, 那麼如果解釋清楚了索引如何能夠幫助做到這幾點,這篇文章的目的就達到了。

不過先不忙著解釋這些,先讓大家成為建索引的高手再說,哈哈,你沒看錯,成為索引高手就這麼簡單,三招速成,再多我也不會了,練完三招後上面這個問題也自然解釋清楚了,好, 讓我們拿下面的查詢SQL來開始練招吧。

SELECT CNO, FNAME

FROM CUST

WHERE LNAME = :LNAME AND CITY = :CITY

ORDER BY FNAME

第一招就是構建一星索引,根據where後面等值的條件,或者範圍的條件來構建索引,即index(LNAME,CITY) 。教科書上一般都說索引是為了能以最快的速度定位到想要的資料,即用空間來換時間,這當然沒錯,但是你有沒有想過,快速定位了你想要的資料後,也就過濾掉了不必要的資料,所以一星索引的核心就是利用索引來儘可能的過濾不必要的資料,減少資料處理的規模,對於RDBMS來說是極為關鍵的,比如說CUST表有1000000行,CITY的過濾度是10%,LNAME的過濾度是0.1%,那麼如果沒有索引,你不得不把表裡所有的一百萬行資料都讀出來,做處理,但是如果有了這個一星索引,需要處理的資料被極大的縮小了,只需要根據索引找到符合條件的索引葉子節點的範圍,讀取0.1%*10%*1000000=100rows就可以了,哪怕我們樂觀的假定產生的都是邏輯IO, 而不是物理IO,單次的差別就已經很明顯了,更別說是執行頻率很高的時候了,我們線上很多爛SQL對DB造成了影響,一看機器邏輯讀都好幾百萬了,基本上就可以定位是SQL索引缺失,或者不合理造成的。當理解了這個時候,你就一定不會產生一個誤區,在硬體越好越好,時延越來越低的今天,是不是索引還有存在的必要。

第二招就是構建二星索引, 針對上面的case, 我們構建索引如下index(LNAME,CITY,FNAME),基本的想法就是利用索引的有序性,把消除ordby或者group by等需要排序的操作,因為大家都知道排序是非常消耗CPU資源的,大量的排序操作會把user cpu搞得很高,即使CPU吃得消,如果資料量比較大,需要排序的資料放不下記憶體的sort buffer,只能悲劇的和外存換進換出,效能下降的就不是一點兩點了,這時候利用索引避免排序的優勢就明顯的體現出來了。

想必第三招你沒學就已經會了,沒錯,第三招就是構建三星索引,即index(LNAME,CITY,FNAME,CNO), 跟之前的二星索引的差別在於, 在索引中額外添加了要查詢的列CNO,這就是所謂的索引覆蓋,即在索引的葉子節點就能夠讀到查詢SQL所需要的所有資訊,而不需要回原表去查詢了,在目前記憶體如此充足的情況下,很多時候,除了root節點和branch結構,甚至整個索引都是可以被放入記憶體的,這樣能大概率的避免,至少是減少物理IO。

也許你會說,這招式都是最理想的狀態,現實的SQL千變萬化,有各種奇葩的條件,有很多動態的SQL,有多表關聯的SQL,肯定不能拿上面說的三腳貓的招數硬往上套, 沒錯,實際情況下確實要考慮這樣那樣的因素,我們也沒辦法構建所有的索引都是三星的,我們只能根據實際情況, 構建最佳的索引,而非理想的索引,但是萬變不離其宗,理解了這三招的原理,就能夠見招拆招了,無招勝有招了。比如各種奇葩的條件,那我們選擇那些過濾性最好的, 比如動態的SQL,我們就抓住主幹的那些SQL,比如兩表關聯(MySQL), 因為那就nest loop一種,那就用小表驅動大表,在關聯欄位各自盡可能的構建最優索引。 

我們前面也提到了,索引其實是一種權衡,是一種拿空間來換時間的藝術,所以極左或者極右都是不恰當的,建立過多的索引所帶來的空間損耗 ,和對DML所產生的負擔,在某些極端場景下,都不能被忽視, 對於DML效能損耗的優化,除了只建立必要的索引外,有些NOSQL實現了二級索引,但是索引是採用非同步方式維護,不在一個事務裡,這是通過犧牲強一致性來提高效能, 但是RDBMS還做不到,另外在innodb上,我們會推薦使用業務無關的自增欄位來作為主鍵,提高順序插入效能的同時,還能避免過多的索引分裂。對於空間成本上的優化,同樣可以有些技巧,還是拿Innodb舉例,我們推薦使用數字型主鍵,而不推薦使用大欄位作為主鍵的重要原因在於,大欄位主鍵會極大的增大二級索引所佔用的空間,因為二級索引葉子節點包含指向的主鍵,另外在Oracle上,我們會定期rebuild index來節省索引所佔用的空間。

同時B+tree索引,作為一種面向磁碟&SSD的資料結構,相對來說,查詢和寫入效能也是相對比較平衡的,讀寫的時間複雜度都在O(log2n),寫入上因為採用的是update-in-place的方式 ,每次寫入的時候需要先通過隨機查詢來找到要寫入的位置,效能會不是那麼好,當然你也可以選擇類似lsm_tree這樣的實現(包括OB自己實現的Btree),通過犧牲一定程度的讀效能,來提高寫的效能。未來會不會出現一種能更完美的資料結構,能夠同時更高效的支援讀取和寫入,是一件比較值得期待的事情。

說了這麼多, 總結一下,我認為那麼在不考慮業務層面優化的前提假設下,索引是最有效的藥方,其他的優化方式與之相比都只能是看成偏方了,而且B-tree作為普遍採用的資料結構,基本上是通用於多種關係型資料庫的,記得我從Oracle轉MySQL的時候,索引的運用基本上能平滑過渡,所以希望大家都能瞭解到這些索引知識, 對平時的工作中寫出更好更合理的SQL會很有幫助。

相關推薦

資料庫個人理解的之路

      偶然和朋友聊到了最近的工作,她是一個db,現在專注於資料庫業務,對未來的進階方向沒有任何的思路,恰好我最近面試,加之新公司自己研發了一個數據庫,最近在學習這方面的東西,有了一些想法和體會。         我個人理

學習資料庫從入門到書籍pdf版吐血整理推薦(珍藏版)

前言: 技術書閱讀方法論 一.速讀一遍(最好在1~2天內完成) 人的大腦記憶力有限,在一天內快速看完一本書會在大腦裡留下深刻印象,對於之後複習以及總結都會有特別好的作用。 對於每一章的知識,先閱讀標題,弄懂大概講的是什麼主題,再去快速看一遍,不懂也沒有關係,但是一定

Linux從零到高手心得

從 2006 年畢業至今,從事 IT 行業已經接近 8 個年頭。一路走來有很多心路歷程和技術心得都寫在了 51CTO 的部落格中,不少文字現在看來已顯稚嫩,但是這正是我真實的成長之路。這八年,從最基礎的網路管理員開始,從最下層的 IT 工作比如說做水晶頭做起,慢慢的走過國企、幹過外企,做過網路管理員、系統工

Linux系統從零到高手心得

初次瞭解到Linux系統還是在我初中的時候,那時候正是在一箇中二年齡,喜歡看小說,對於小說中出現的明顯的非現實場景感到十分欽佩、羨慕,並常常幻想自己也有小說主人公那樣的本領。那正是在這樣一個充滿幻想的年紀,我看到了一本關於重生、關於黑客的小說。書中的主人公絕處逢生,帶著記

成為阿里雲架構師的之路——阿里雲首批ACE認證通過者逸疏專訪

自2018年3月阿里雲釋出雲端計算架構師ACE(Alibaba Cloud Certified Expert,阿里雲認證高階工程師)級別認證後,上線不到3個月,吸引了近百位業界優秀從業者參與考試。獲得阿里雲ACE認證,對於業界資深架構師來說,是自身實力的最好證明。阿里雲大學致

如何成為資料庫索引高手資料庫

今天來聊聊資料庫裡的索引,你知道的,網上這樣的文章一抓一大把的, 基本都是從索引的原理說起,講到索引的分類, 物理組織和儲存形式,如何找到對應的記錄,如何構建複雜的索引等等 ,如果我再寫一篇這樣的就沒意思了,而且這些未必真的是大家(尤其是開發同學)關心的。所以我今天打算以

SQL Server調優系列篇(如何維護資料庫索引

前言 上一篇我們研究瞭如何利用索引在資料庫裡面調優,簡要的介紹了索引的原理,更重要的分析瞭如何選擇索引以及索引的利弊項,有興趣的可以點選檢視。 本篇延續上一篇的內容,繼續分析索引這塊,側重索引項的日常維護以及一些注意事項等。 閒言少敘,進入本篇的主題。 技術準備 資料庫版本為SQL Server20

第四模組:網路程式設計&資料庫開發 口述

子程序死了之後 ,父程序關閉的時候要清理掉子程序的殭屍程序(收屍),孤兒程序是指父程序先死掉了的,交給init管理。 join() 等待子程序結束後才執行主程序下面的程式碼 即使可以利用的cpu只有一個(早期的計算機確實如此),也能保證支援(偽)併發的能力。將一個單獨的cpu變成多個虛擬的cpu(多道技術

mongodb 索引導致資料庫阻塞

在MongoDB上建索引可能會對MongoDB叢集對可用性產生負面影響。在生產服務上,如果針對一個大集合觸發建立索引,且在前臺執行,你可能會發現,在索引建完之前,整個叢集都無影響。在一個大集合上,這個過程可能會持續幾個小時,甚至幾天。 解決的方法很簡單,MongoDB 提供了兩種建索引的訪問,一

Python(二十二)-Python3使用PyMysql連線mysql資料庫

分享一下我的偶像大神的人工智慧教程!http://blog.csdn.net/jiangjunshow 也歡迎轉載我的文章,轉載請註明出處 https://blog.csdn.net/mm2zzyzzp Python進階(二十二)-Python3使用PyMys

學習資料庫Mysql/Oracle/SQL從入門到書籍pdf版吐血整理推薦附網盤連結(珍藏版)

轉載自某大佬部落格:https://pymlovelyq.github.io/2018/10/12/database/ 前言:技術書閱讀方法論 一.速讀一遍(最好在1~2天內完成) 人的大腦記憶力有限,在一天內快速看完一本書會在大腦裡留下深刻印象,對於之後複習以及總結

學習資料庫Mysql/Oracle/SQL從入門到書籍pdf版吐血整理推薦(珍藏版)

轉載自某大佬部落格:https://pymlovelyq.github.io/2018/10/12/database/ 前言:技術書閱讀方法論 一.速讀一遍(最好在1~2天內完成) 人的大腦記憶力有限,在一天內快速看完一本書會在大腦裡留下深刻印象,對於之後複習以及總結

java程式設計師菜鳥(五)oracle基礎詳解(五)oracle資料庫體系架構詳解

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

PHP自己封裝一個原生mysql資料庫工具類--常用類仿PDO模式

<?php header('content-type:text/html;charset=utf-8'); error_reporting(E_ALL ^ E_DEPRECATED); // 設計一個mysql資料庫操作類 $config=array(     'hos

【技能圖譜免費下載】資料庫工程師 你需要Get這些技能

所謂DBA,就是我們通常說的資料庫管理員,主要從事資料庫安裝、管理、調優、備份、容災、叢集、安全等。DBA除了對資料庫本身比較熟悉外,還要對硬體(主機、儲存、網路)、作業系統等方面有較好的理解,否則很難成為真正的高手。 傳統DBA必備技能 傳統工作模式下,DBA需要為企業搭建一套高可用性(HA)、高效能的

資料庫操作

點我跳轉到資料庫的基本操作 文章目錄 使用as給欄位起別名 使用as給表起別名 消除重複行 條件查詢 條件中加入判斷 常用的比較運算子 邏輯運算子 模糊查詢like

毛毛Python之路6——MySQL 資料庫(二)

毛毛Python進階之路6——MySQL 資料庫(二) 一、對於自增 show create table 表名; # 查看錶是怎樣建立的。 show create table 表名\G; #將某個表旋轉90度 alter table 表名 AUTO_INCREMENT=

毛毛Python之路6——MySQL 資料庫(一)

毛毛Python進階之路6——MySQL 資料庫(一) DBMS 系統:資料庫管理系統。 一、安裝和下載: MySQL有兩種安裝方式,一種可執行檔案(點點點就可以),另一種是壓縮包式,需要有一定的基礎,比如新增環境變數,新增程序等等。 1、新增環境變數:計算機屬性-高階系統

【JDBC程式設計】Java 連線 MySQL資料庫基礎、入門和

Content: 常用的JDBC API 資料庫環境的搭建 建立資料庫連線 資料庫訪問優化 一. 常用的JDBC API 1. DriverManager類 : 資料庫管理類,用於管理一組JDBC驅動程式的基本服務。應用程式和資料

mysql(十一)外來鍵在資料庫中的作用

MySQL外來鍵在資料庫中的作用      MySQL外來鍵的目的是控制儲存在外來鍵表中的資料,使兩張表形成關聯,是MySQL資料庫中非常重要的組成部分,值得我們去深入瞭解。那麼,MySQL外來鍵究竟起到哪些作用呢?下文就將帶您一探其中的祕密。MySQL外來鍵的作用