什麼是DB的三星索引

上一篇《Sql優化器究竟幫你作了哪些工做?》講解了,sql優化器所作的工做,有很多同窗詢問,爲什麼沒有看到如何設計索引,這一篇主要來說解下索引設計中須要遵循的規範。sql

這是數據庫設計第三篇:數據庫

《Sql優化器究竟幫你作了哪些工做?》緩存

《DB——數據的讀取和存儲方式》數據庫設計

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

本篇嘗試從《Relational Database index design and the optimizers》書中提到的三星索引,提煉出索引設計的準則和原理,期待可以對索引設計準則起到一個錨定做用,期待你們一塊兒探討學習。優化

從本文,你能夠學習到:spa

  1. 什麼是三星索引.net

  2. 三星索引的原理是什麼設計

  3. 如何設計最佳索引code

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;

 

1、失敗的索引應用

咱們假設 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,從上一篇《》中,咱們知道隨機IO會佔用大量的查詢時間的。

 

咱們不考慮數據庫緩存以及磁盤緩存

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

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

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

 

2、三星索引

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

若是查詢使用三星索引,一次查詢一般只須要進行一次磁盤隨機讀以及一次窄索引片的掃描,所以其相應時間一般比使用一個普通索引的響應時間少幾個數量級。

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

 

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

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

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

 

三顆星的意義

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

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

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

 

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

 

好比咱們上述的查詢:

select user_name,sex,c_date from test where user_name ='test0' order by sex;
​
最終須要的三星索引是:
​
(user_name,sex ,c_date)

 

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

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

現實狀況每每很難達到三星索引,咱們分狀況來進行說明。一般狀況下,第三顆星(索引行包含查詢語句中全部的列)是最容易達成的,第2、三星每每不可以一塊兒達成。

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

 

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

(user_name,sex,age)

 

三星索引對齊:

  • 第三顆星,知足,select查詢的列都在索引列中

  • 第一顆星,知足,user_name 能夠匹配到一個索引列列 user_name和一個過濾列sex,他們是相鄰的

  • 第二顆星,不知足,user_name 採用了範圍匹配,sex 是過濾列,此時age 列並非有序的,不知足 order by age要求

 

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

 

索引2(知足第2、三顆星,無窄索引片)

(sex,ageuser_name)

 

三星索引對齊:

  • 第一顆星,不知足,只能夠匹配到sex 索引列,sex索引列是一個寬索引片

  • 第二顆星,知足,等值sex 的狀況下,age是有序的

  • 第三顆星,知足,select查詢的列都在索引列中

對於索引(sex,ageuser_name)咱們能夠看到,此時沒法知足第一顆星,窄索引片的需求。

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

 

3、寬索引

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

這顆星很好達到,又很難把控。或者說,爲了達到這顆星,是否應該把全部的列都設計到索引列裏面?

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

但劣勢也很明顯,長列索引會形成頻繁的page split 和 page merge ,每一個page可以存入的索引數據更少,並且會有更多的 page split,這對插入和查詢來講,效率都會下降很多。

那咱們應該怎麼作,咱們要回顧索引設計的本心,設計索引是爲了方便查詢的,而不是隻爲設計索引,脫離了查詢的索引設計,並不高效。

寬索引要求咱們儘可能包含多的列在索引中,並非全部,因此除了針對where 後的經常使用謂詞,咱們要設計索引之外,咱們還得爲經常使用select 後面的謂詞,加入到索引,以加快查詢速度。

相關文章
相關標籤/搜索