什麼是三星索引

2021-02-14 ByteThink

上一篇《Sql優化器究竟幫你做了哪些工作?》,講解了sql優化器所做的工作,有不少同學詢問,為何沒有看到如何設計索引,這一篇主要來講解下索引設計中需要遵循的規範。

如果你從網上或者教程中,查詢索引設計相關規範,常常會看到一些不知所云的規則和注意事項,這些規則看似很有道理,但等你應用時,會發現仍然讓你一頭霧水,不知如何下手,就像我們提到的知識的邊界一樣,這些乾澀的知識點,對我們的索引設計並沒有任何幫助,只能令DB新手望而卻步。

本篇嘗試從《Relational Database index design and the optimizers》書中提到的三星索引,提煉出索引設計的準則和原理,期待能夠對學習索引設計時候提供一個錨點,期待大家一起探討學習。

從本文,你可以學習到:

什麼是三星索引

三星索引的原理是什麼

如何設計最佳索引


table
CREATE TABLE `test` (

 `id` int(11) NOT NULL AUTO_INCREMENT,

 `user_name` varchar(100) DEFAULT NULL,

 `sex` int(11) DEFAULT NULL,

 `age` int(11) DEFAULT NULL,

 `c_date` datetime DEFAULT NULL,

 PRIMARY KEY (`id`),

 # 索引

 KEY `id_name_sex` (`id`,`user_name`,`sex`),

 KEY `name_sex_age` (`user_name`,`sex`,`age`)

) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8;


一、失敗的索引應用


我們假設 talbe test 裡面有10000行數據,其中 user_name 有100種不同的值,其FF=1%,我們查看以下兩個sql:


sql1: select user_name,sex,c_date from test where user_name ='test0' order by sex

sql2: select user_name,sex,c_date from test


以上我們可以預測到:

sql1 要比sql2 的查詢速度快,因為sql用到了索引name_sex_age ,而sql2 是全表掃描。

那麼真實情況是這樣麼?

我們加上查詢列印時間,查看下:


select user_name,sex,c_date from test where user_name ='test0' order by sex;

101 rows in set (0.02 sec)

select user_name,sex,c_date from test;

10013 rows in set (0.01 sec)


以上我們可以看到,全表掃描(sql2)的耗時要低於用索引(sql1)的耗時,這是為何?

sql1 中,雖然用到了索引,但用的是輔助索引name_sex_age,  再加上 select的時候是全行查詢,所以從索引片檢索出數據之後,還要去聚簇索引中查詢一次,這就產生了大量的隨機IO,從上一篇《DB——數據的讀取和存儲方式》中,我們知道隨機IO會佔用大量的查詢時間的。


我們不考慮資料庫緩存以及磁碟緩存

sql1 查詢耗時=10ms(第一次查索引IO)+0.01ms100(索引行,順序讀取)+10010ms(主表隨機讀) =1010 ms

sql2 查詢耗時=10ms(第一次查索引IO)+0.01ms*10000(索引行,順序讀取)=110 ms

那麼我該如何設計我們的索引,以及查詢?


二、三星索引


對於一個查詢而言,一個三星索引,可能是其最好的索引。

如果查詢使用三星索引,一次查詢通常只需要進行一次磁碟隨機讀以及一次窄索引片的掃描,因此其相應時間通常比使用一個普通索引的響應時間少幾個數量級。

那麼索引的星級是如何定義?


第一顆星:與查詢相關的索引行是相鄰的,也就是where後面的等值謂詞,可以匹配索引列順序

第二顆星:索引行的順序與查詢語句需求一致,也就是order by 中的排序和索引順序是否一致

第三顆星:索引行包含查詢語句中所有的列


三顆星的意義

第一顆星,也是我們上篇文章所提的匹配列,where後面的謂詞和索引列匹配的越多,索引片越窄,最終掃描的數據行也是越小

第二顆星,是避免排序,如果結果集採用現有順序讀取,那麼就會避免一次排序,避免提前物化結果集

第三顆星,避免每一個索引行查詢,都需要去聚簇索引進行一次隨機IO查詢


上述中第三顆星也是我們常說的寬索引,它可以保證查詢只需訪問索引而無需訪問表。


比如我們上述的查詢:


select user_name,sex,c_date from test where user_name ='test0' order by sex;

最終需要的三星索引是:

(user_name,sex ,c_date)


三、最佳索引——多種方案

三星索引是一種理想的索引設計方式,真實情況中往往很難達到,它是一個標尺或者是引路人的方式,要求我們設計索引時必須要注意的要素。

現實情況往往很難達到三星索引,我們分情況來進行說明。通常情況下,第三顆星(索引行包含查詢語句中所有的列)是最容易達成的,第二、三星往往不能夠一起達成。


select user_name,sex,age from test where user_name like 'test%'  and sex =1 ORDER BY age


索引1,(滿足第一、三顆星,無排序)

(user_name,sex,age)

三星索引對齊:


上述我們看到,此時索引(user_name,sex,age)並不能滿足三星索引中的第二顆星(排序),想要滿足必須得讓 age 列在 user_name 列前面,索引我們才去方案2


索引2(滿足第二、三顆星,無窄索引片

(sex,age,user_name)

三星索引對齊:

對於索引(sex,age,user_name)我們可以看到,此時無法滿足第一顆星,窄索引片的需求。

以上2個索引,都是無法同時滿足三星索引設計中的三個需求的,我們只能盡力滿足2個。而在多數情況下,能夠滿足2顆星,已經能縮小很大的查詢範圍了,具體最終要保留那一顆星(排序星 or 窄索引片星),這個就需要看查詢者自己的著重點了,無法給出標準答案。

三、寬索引

在三星索引中,第三顆星要求(索引行包含查詢語句中所有的列),也就是常說的寬索引。

這顆星很好達到,又很難把控。或者說,為了達到這顆星,是否應該把所有的列都設計到索引列裡面?

如果每個索引中包含表的所有列,首先能帶來的優勢是,匹配到的sql查詢更多,查詢到的數據不用在進行聚簇索引查詢,節省了隨機IO。

但劣勢也很明顯,長列索引會造成頻繁的page split 和 page merge ,每個page能夠存入的索引數據更少,而且會有更多的 page split,這對插入和查詢來說,效率都會降低不少。

那我們應該怎麼做,我們要回顧索引設計的本心,設計索引是為了方便查詢的,而不是只為設計索引,脫離了查詢的索引設計,並不高效。

寬索引要求我們儘量包含多的列在索引中,並不是所有,所以除了針對where 後的常用謂詞,我們要設計索引以外,我們還得為常用select 後面的謂詞,加入到索引,以加快查詢速度。
最近相關文章:《Sql優化器究竟幫你做了哪些工作?》《DB——數據的讀取和存儲方式》

關注遊戲研發和個人成長,掃描二維碼,關注更多原創文章。

相關焦點

  • 如何預估索引性能?
    在《什麼是三星索引》介紹了索引設計需要主要的因素以及推薦的設計方式。那麼這篇,我們將綜合運用這些知識,並通過兩個方法,快速估算當前的索引的性能,以及查詢的效率。上述中where後面的謂詞都包含在索引(name,sex,age),但這個查詢卻是一個全索引或者全表掃描,三星中一個都不佔有。具體原因,可以查看《Sql優化器究竟幫你做了哪些工作?》中的介紹。
  • MySQL 索引設計概要
    三星索引三星索引是對於一個查詢語句可能的最好索引,如果一個查詢語句的索引是三星索引,那麼它只需要進行一次磁碟的隨機讀及一個窄索引片的順序掃描就可以得到全部的結果集;因此其查詢的響應時間比普通的索引會少幾個數量級;根據書中對三星索引的定義,我們可以理解為主鍵索引對於 WHERE id = 1 就是一個特殊的三星索引,我們只需要對主鍵索引樹進行一次索引訪問並且順序讀取一條數據記錄查詢就結束了
  • 網站索引是什麼意思?有效索引又是什麼鬼?
    現在百度抓取到本地並進行索引的網頁已經以千億計,如果每一個用戶提交查詢時,百度搜索從這幾千億個網頁中進行檢索,相信不論百度的伺服器集群多麼牛,都不能快速響應。即使勉強能夠滿足用戶的搜索,反應速度和效率肯定非常低。因此為了解決這個問題,搜尋引擎會引入有效索引和緩存模塊。
  • 什麼是 MySQL 索引?
    什麼是索引?
  • 如何快速預估索引性能及查詢效率
    介紹了影響查詢的一些基本因素,其中介紹了過濾因子、索引片的寬窄與大小以及匹配列和過濾列 是如何應用在sql查詢中的。在《什麼是三星索引》介紹了索引設計需要主要的因素以及推薦的設計方式。那麼這篇,我們將綜合運用這些知識,並通過兩個方法,快速估算當前的索引的性能,以及查詢的效率。
  • MySQL的索引到底是什麼?
    文章結構如下:1 概念什麼是索引索引似乎並沒有十分明確的定義,更多的是一種定性的描述。簡單來講,索引就是一種將資料庫中的記錄按照特殊形式存儲的數據結構。通過索引,能夠顯著地提高數據查詢的效率,從而提升伺服器的性能。
  • MySQL,多列索引
    多列索引我們後續會單獨討論索引列的順序問題。條件裡面的列都建上索引」這樣模糊的建議導致的。這樣一來 最好的情況下也只能是「一星」索引,其性能比起真正最優的索引可能差幾個數量級。有時如果無法設計一個「三星」索引,那麼不如忽略掉WHERE子句,集中精力優化索引列的順序,或者創建一個全覆蓋索引。在多個列上建立獨立的單列索引大部分情況下並不能提高MySQL的查詢性能。
  • 什麼B+樹索引,為什麼MySQL使用B+樹索引,而MongoDB缺還是使用B樹索引
    什麼是B+樹索引,很多人在面試的時候總時被問到,也有很多人是說不清楚的。
  • MySQL 的索引是什麼?怎麼優化?
    索引類似大學圖書館建書目索引,可以提高數據檢索的效率,降低資料庫的IO成本。MySQL在300萬條記錄左右性能開始逐漸下降,雖然官方文檔說500~800w記錄,所以大數據量建立索引是非常有必要的。MySQL提供了Explain,用於顯示SQL執行的詳細信息,可以進行索引的優化。1.硬體問題。如網絡速度慢,內存不足,I/O吞吐量小,磁碟空間滿了等。
  • MySQL索引與索引優化
    MySQL的基本架構示意圖MySQL索引就是用於優化器上。索引:MySQL官方對於索引的定義為:索引是幫助MySQL高效獲取數據的數據結構。即可以理解為:索引是數據結構。索引是對資料庫表中一個或多個列的值進行排序的結構,建立索引有助於快速獲取信息。你也可以這樣理解:索引就是加快檢索表中數據的方法。資料庫的索引類似於書籍的索引。在書籍中,索引允許用戶不必翻閱完整個書就能迅速地找到所需要的信息。在資料庫中,索引也允許資料庫程序迅速地找到表中的數據,而不必掃描整個資料庫。
  • MySQL中的索引原理與索引分類
    因為更新表時,MySQL不僅要保存數據,還要保存一下索引列的欄位,都會調整因為更新所帶來的鍵值變化後的索引信息。3. 什麼時候建立索引索引是應用程式設計和開發的一個重要方面。若索引太多,應用程式的性能可能會受到影響。而索引太少,對查詢性能又會產生影響,要找到一個平衡點,這對應用程式的性能至關重要。
  • MySQL:你知道什麼是覆蓋索引嗎?
    什麼叫做覆蓋索引?解釋一: 就是select的數據列只用從索引中就能夠取得,不必從數據表中讀取,換句話說查詢列要被所使用的索引覆蓋。解釋二: 索引是高效找到行的一個方法,當能通過檢索索引就可以讀取想要的數據,那就不需要再到數據表中讀取行了。如果一個索引包含了(或覆蓋了)滿足查詢語句中欄位與條件的數據就叫做覆蓋索引。
  • ElasticSearch 索引 VS MySQL 索引
    說的不是很透徹,沒有解析相關的原理;不過既然反覆提到了索引,那我們就從索引的角度來對比下兩者的差異。MySQL 索引先從 MySQL 說起,索引這個詞想必大家也是爛熟於心,通常存在於一些查詢的場景,是典型的空間換時間的案例。
  • MySQL 面試索引全篇,索引面試掌握這些就夠了
    問:可以說說聚集索引和非聚集索引區別嗎?在 Mysql 中,有兩大常用的存儲引擎 MyisAm 和 Innodb , Myisam 使用的是非聚集索引也叫非聚簇索引, InnoDb 使用的是聚集索引,聚集索引就是以主鍵創建的索引,非聚集索引就是除了主鍵以外的索引。
  • Mysql面試題:聚簇索引與聚簇索引、覆蓋索引、組合索引-開課吧
    聚簇索引:key為主鍵,value為其餘列的數據。 個表只能有個聚簇索引。聚簇索引:除了聚簇索引外的都叫聚簇索引 。對於MyISAM的主鍵索引來說,它的聚簇索引是key為主鍵,value為號(不定) 。
  • 施工圖中索引符號與詳圖符號是什麼
    問:施工圖中索引符號與詳圖符號是什麼?  答:在施工圖中,有時會因為比例問題而無法表達清楚某一局部,為方便施工需另畫詳圖。一般用索引符號註明畫出詳圖的位置、詳圖的編號以及詳圖所在的圖紙編號。索引符號和詳圖符號內的詳圖編號與圖紙編號兩者對應一致。  按「國標」規定,索引符號的圓和引出線均應以細實線繪製,圓直徑為10mm。
  • 圖解MySQL索引:如何正確使用索引?
    由於索引也是需要佔用內存的,所以在內存較為有限的環境下,區分度不高的索引幾乎沒有意義。聯合索引優先於多列獨立索引聯合索引優先於多列獨立索引, 假設有三個欄位a,b,c, 索引(a)(a,b),(a,b,c)可以使用(a,b,c)代替。
  • SEO的索引和抓取是什麼意思,外貿自建站如何優化索引和抓取?
    抓取和索引這兩件事就是SEO領域中簡單而又重要的觀念,熟悉了解它們之後便可以優化搜尋引擎蜘蛛抓取、索引你的網站。 索引完成之後,用戶才能在搜尋引擎中找到你的網站,簡單來講,先有抓取才會有索引,通過Google站長工具,我們可以看到網站被抓取、索引的情況。 抓取和索引是完全不同的兩件事,有可能你的頁面被Google正常抓取,卻沒有將頁面索引到搜尋引擎上,這樣的情況一般來講就很有可能是你的網站有違規的行為,又或者排名太差,在搜尋引擎上根本找不到自己的頁面。
  • 你說你熟悉MySQL索引,給我講講創建索引時應該注意什麼?
    也就是說,在這個查詢裡面,索引 k 已經「覆蓋了」我們的查詢需求,我們稱為覆蓋索引。也就是說,索引已經包含所有需要查詢的欄位的值,只讀取索引就能夠查詢到需要的值。由於覆蓋索引可以減少樹的搜索次數,顯著提升查詢性能,所以使用覆蓋索引是一個常用的性能優化手段。
  • Mysql索引:圖文並茂,深入探究索引的原理和使用
    1 索引原理探究什麼是資料庫索引?先來個官方一些的定義吧。1.2 聚簇索引與非聚簇索引首先,為了方便理解,我們先了解一下聚集索引(clustered index)和非聚集索引(secondary index,也稱輔助索引或普通索引)。這兩種索引是按存儲方式進行區分的。聚集索引(clustered)也稱聚簇索引,這種索引中,資料庫表行中數據的物理順序與鍵值的邏輯(索引)順序相同。