理解Mysql的單索引和複合索引

 

Mysql數據庫提供兩種類型的索引,若是沒正確設置,索引的利用效率會大打折扣卻徹底不知問題出在這。php

代碼以下:mysql

CREATE TABLE test (
    id         INT NOT NULL,
    last_name  CHAR(30) NOT NULL,
    first_name CHAR(30) NOT NULL,
    PRIMARY KEY (id),
    INDEX name (last_name,first_name)
);


以上建立的實際上是一個多列索引,建立列索引的代碼以下:sql

代碼以下:數據庫

CREATE TABLE test (
    id         INT NOT NULL,
    last_name  CHAR(30) NOT NULL,
    first_name CHAR(30) NOT NULL,
    PRIMARY KEY (id),
    INDEX name (last_name),
     INDEX_2 name (first_name)
);


一個多列索引能夠認爲是包含經過合併(concatenate)索引列值建立的值的一個排序數組。 當查詢語句的條件中包含last_name 和 first_name時,例如:數組

代碼以下:性能優化


SELECT * FROM test WHERE last_name='Kun' AND first_name='Li';


sql會先過濾出last_name符合條件的記錄,在其基礎上在過濾first_name符合條件的記錄。那若是咱們分別在last_name和first_name上建立兩個列索引,mysql的處理方式就不同了,它會選擇一個最嚴格的索引來進行檢索,能夠理解爲檢索能力最強的那個索引來檢索,另一個利用不上了,這樣效果就不如多列索引了。

可是多列索引的利用也是須要條件的,如下形式的查詢語句可以利用上多列索引:服務器

代碼以下:網絡


SELECT * FROM test WHERE last_name='Widenius';
SELECT * FROM test WHERE last_name='Widenius' AND first_name='Michael';
SELECT * FROM test WHERE last_name='Widenius' AND (first_name='Michael' OR first_name='Monty');
SELECT * FROM test WHERE last_name='Widenius' AND first_name >='M' AND first_name < 'N';


如下形式的查詢語句利用不上多列索引:mysql優化

代碼以下:併發

SELECT * FROM test WHERE first_name='Michael';
SELECT * FROM test WHERE last_name='Widenius' OR first_name='Michael';

 


多列建索引比對每一個列分別建索引更有優點,由於索引創建得越多就越佔磁盤空間,在更新數據的時候速度會更慢。

當咱們執行查詢的時候,MySQL只能使用一個索引。若是你有三個單列的索引,MySQL會試圖選擇一個限制最嚴格的索引。可是,即便是限制最嚴格的單列索引,它的限制能力也確定遠遠低於firstname、lastname、age這三個列上的多列索引。

另外創建多列索引時,順序也是須要注意的,應該將嚴格的索引放在前面,這樣篩選的力度會更大,效率更高。

 

對於要常常查詢的含量大量數據的數據庫,創建索引是很是重要的,創建索引通常都是在where語句用得較多的列上。如今有個問題,若是一個表有多個列須要創建索引,是把全部列建成一個索引,仍是對每個列建一個索引,上篇文章作了一個介紹,這是做者得出的結論,Conclusion: For benchmarked queries we can see Multiple Column index beats Index Merge in all cases when such index can be used. It is also worth to watchout a MySQL may decide not to do Index merge (either intersection or union) but instead do full table scan or access table picking only one index on the pair.意思應該是說對多個列建索引比對每一個列分別建索引更有優點,並且要知道索引創建得越多就越佔磁盤空間,在更新數據的時候速度會更慢。
tb表有1700條記錄,foo字段有750個不一樣的記錄,那麼就能夠說We have a cardinality of 750 for foo。總規則能夠說是cardinality越大的字段應該排在索引的第一位就是說索引的位置是(foo,bar),由於cardinality越大那麼第一次取出來的記錄集就越小,再進行第二次查詢的次數就越少了。

 

考慮數據列的基數(cardinality)。基數是數據列所包含的不一樣值的數量。例如,某個數據列包含值一、三、七、四、七、3,那麼它的基數就是4。索引的基數相對於數據錶行數較高(也就是說,列中包含不少不一樣的值,重複的值不多)的時候,它的工做效果最好。若是某數據列含有不少不一樣的年齡,索引會很快地分辨數據行。若是某個數據列用於記錄性別(只有"M"和"F"兩種值),那麼索引的用處就不大。若是值出現的概率幾乎相等,那麼不管搜索哪一個值均可能獲得一半的數據行。在這些狀況下,最好根本不要使用索引,由於查詢優化器發現某個值出如今表的數據行中的百分比很高的時候,它通常會忽略索引,進行全表掃描。慣用的百分比界線是"30%"。如今查詢優化器更加複雜,把其它一些因素也考慮進去了,所以這個百分比並非MySQL決定選擇使用掃描仍是索引的惟一因素。

 

 

 

最左前綴

  多列索引還有另一個優勢,它經過稱爲最左前綴(Leftmost Prefixing)的概念體現出來。繼續考慮前面的例子,如今咱們有一個firstname、lastname、age列上的多列索引,咱們稱這個索引爲fname_lname_age。當搜索條件是如下各類列的組合時,MySQL將使用fname_lname_age索引:

 

  • firstname,lastname,age
  • firstname,lastname
  • firstname

再多說幾句組合索引的最左優先原則:
組合索引的第一個字段必須出如今查詢組句中,這個索引纔會被用到。
若是有一個組合索引(col_a,col_b,col_c)

下面的狀況都會用到這個索引:
col_a = "some value";
col_a = "some value" and col_b = "some value";
col_a = "some value" and col_b = "some value" and col_c = "some value";
col_b = "some value" and col_a = "some value" and col_c = "some value";

對於最後一條語句,mysql會自動優化成第三條的樣子~~。

  從另外一方面理解,它至關於咱們建立了(firstname,lastname,age)、(firstname,lastname)以及(firstname)這些列組合上的索引。下面這些查詢都可以使用這個fname_lname_age索引:

SELECT peopleid FROM people WHERE firstname='Mike' AND lastname='Sullivan' AND age='17'; SELECT peopleid FROM people WHERE firstname='Mike' AND lastname='Sullivan'; SELECT peopleid FROM people WHERE firstname='Mike'; The following queries cannot use the index at all: SELECT peopleid FROM people WHERE lastname='Sullivan'; SELECT peopleid FROM people WHERE age='17'; SELECT peopleid FROM people WHERE lastname='Sullivan' AND age='17';

 

 

 

選擇索引列

 

  在性能優化過程當中,選擇在哪些列上建立索引是最重要的步驟之一。

 a.考慮使用索引的主要有兩種類型的列:在WHERE子句中出現的列,在join子句中出現的列。

 b.考慮列中值的分佈,索引的列的基數越大,索引的效果越好。 

 c.使用短索引,若是對字符串列進行索引,應該指定一個前綴長度,可節省大量索引空間,提高查詢速度。 

 d.利用最左前綴 

 e.不要過分索引,只保持所需的索引。每一個額外的索引都要佔用額外的磁盤空間,並下降寫操做的性能。 

  在修改表的內容時,索引必須進行更新,有時可能須要重構,所以,索引越多,所花的時間越長。 

請看下面這個查詢:

 

SELECT age ## 不使用索引
FROM people WHERE firstname='Mike' ## 考慮使用索引
AND lastname='Sullivan' ## 考慮使用索引

  這個查詢與前面的查詢略有不一樣,但仍屬於簡單查詢。因爲age是在SELECT部分被引用,MySQL不會用它來限制列選擇操做。所以,對於這個查詢來講,建立age列的索引沒有什麼必要。下面是一個更復雜的例子:

 

SELECT people.age, ##不使用索引
town.name ##不使用索引
FROM people LEFT JOIN town ON
people.townid=town.townid ##考慮使用索引
WHERE firstname='Mike' ##考慮使用索引
AND lastname='Sullivan' ##考慮使用索引

  與前面的例子同樣,因爲firstname和lastname出如今WHERE子句中,所以這兩個列仍舊有建立索引的必要。除此以外,因爲town表的townid列出如今join子句中,所以咱們須要考慮建立該列的索引。

  那麼,咱們是否能夠簡單地認爲應該索引WHERE子句和join子句中出現的每個列呢?差很少如此,但並不徹底。咱們還必須考慮到對列進行比較的操做符類型。MySQL只有對如下操做符才使用索引:<,<=,=,>,>=,BETWEEN,IN,以及某些時候的LIKE。能夠在LIKE操做中使用索引的情形是指另外一個操做數不是以通配符(%或者_)開頭的情形。例如,「SELECT peopleid FROM people WHERE firstname LIKE 'Mich%';」這個查詢將使用索引,但「SELECT peopleid FROM people WHERE firstname LIKE '%ike';」這個查詢不會使用索引。

用or分隔開的條件,若是or前的條件中的列有索引,然後面的列沒有索引,那麼涉及到的索引都不會被用到,例如:select * from table_name where key1='a' or key2='b';若是在key1上有索引而在key2上沒有索引,則該查詢也不會走索引

總結:多列索引只有在where條件中含有索引中的首列字段時纔有效 

 

分析索引效率

  如今咱們已經知道了一些如何選擇索引列的知識,但還沒法判斷哪個最有效。MySQL提供了一個內建的SQL命令幫助咱們完成這個任務,這就是EXPLAIN命令。EXPLAIN命令的通常語法是:EXPLAIN <SQL命令>。你能夠在MySQL文檔找到有關該命令的更多說明。下面是一個例子:

EXPLAIN SELECT peopleid FROM people WHERE firstname='Mike' AND lastname='Sullivan' AND age='17';

  這個命令將返回下面這種分析結果:

  下面咱們就來看看這個EXPLAIN分析結果的含義。

 

    • table:這是表的名字。
    • type:鏈接操做的類型。下面是MySQL文檔關於ref鏈接類型的說明:

      「對於每一種與另外一個表中記錄的組合,MySQL將從當前的表讀取全部帶有匹配索引值的記錄。若是鏈接操做只使用鍵的最左前綴,或者若是鍵不是UNIQUE或PRIMARY KEY類型(換句話說,若是鏈接操做不能根據鍵值選擇出惟一行),則MySQL使用ref鏈接類型。若是鏈接操做所用的鍵只匹配少許的記錄,則ref是一種好的鏈接類型。」

      在本例中,因爲索引不是UNIQUE類型,ref是咱們可以獲得的最好鏈接類型。

      若是EXPLAIN顯示鏈接類型是「ALL」,並且你並不想從表裏面選擇出大多數記錄,那麼MySQL的操做效率將很是低,由於它要掃描整個表。你能夠加入更多的索引來解決這個問題。預知更多信息,請參見MySQL的手冊說明。
    • possible_keys
      可能能夠利用的索引的名字。這裏的索引名字是建立索引時指定的索引暱稱;若是索引沒有暱稱,則默認顯示的是索引中第一個列的名字(在本例中,它是「firstname」)。默認索引名字的含義每每不是很明顯。
    • Key
      它顯示了MySQL實際使用的索引的名字。若是它爲空(或NULL),則MySQL不使用索引。
    • key_len
      索引中被使用部分的長度,以字節計。在本例中,key_len是102,其中firstname佔50字節,lastname佔50字節,age佔2字節。若是MySQL只使用索引中的firstname部分,則key_len將是50。
    • ref
      它顯示的是列的名字(或單詞「const」),MySQL將根據這些列來選擇行。在本例中,MySQL根據三個常量選擇行。
    • rows
      MySQL所認爲的它在找到正確的結果以前必須掃描的記錄數。顯然,這裏最理想的數字就是1。
    • Extra
      這裏可能出現許多不一樣的選項,其中大多數將對查詢產生負面影響。在本例中,MySQL只是提醒咱們它將用WHERE子句限制搜索結果集。

 

 

索引的缺點

  到目前爲止,咱們討論的都是索引的優勢。事實上,索引也是有缺點的。

  首先,索引要佔用磁盤空間。一般狀況下,這個問題不是很突出。可是,若是你建立每一種可能列組合的索引,索引文件體積的增加速度將遠遠超過數據文件。若是你有一個很大的表,索引文件的大小可能達到操做系統容許的最大文件限制。

  第二,對於須要寫入數據的操做,好比DELETE、UPDATE以及INSERT操做,索引會下降它們的速度。這是由於MySQL不只要把改動數據寫入數據文件,並且它還要把這些改動寫入索引文件。

  在大型數據庫中,索引是提升速度的一個關鍵因素。無論表的結構是多麼簡單,一次500000行的表掃描操做不管如何不會快。若是你的網站上也有這種大規模的表,那麼你確實應該花些時間去分析能夠採用哪些索引,並考慮是否能夠改寫查詢以優化應用。

 

 

 

 

 

淺談MySQL中優化sql語句查詢經常使用的30種方法

轉載自:http://www.jb51.net/article/39221.htm

1.對查詢進行優化,應儘可能避免全表掃描,首先應考慮在 where 及 order by 涉及的列上創建索引。 

2.應儘可能避免在 where 子句中使用!=或<>操做符,不然將引擎放棄使用索引而進行全表掃描。 

3.應儘可能避免在 where 子句中對字段進行 null 值判斷,不然將致使引擎放棄使用索引而進行全表掃描,如: 
select id from t where num is null 
能夠在num上設置默認值0,確保表中num列沒有null值,而後這樣查詢: 
select id from t where num=0 

4.應儘可能避免在 where 子句中使用 or 來鏈接條件,不然將致使引擎放棄使用索引而進行全表掃描,如: 
select id from t where num=10 or num=20 
能夠這樣查詢: 
select id from t where num=10 
union all 
select id from t where num=20 

5.下面的查詢也將致使全表掃描: 
select id from t where name like '%abc%' 
若要提升效率,能夠考慮全文檢索。 

6.in 和 not in 也要慎用,不然會致使全表掃描,如: 
select id from t where num in(1,2,3) 
對於連續的數值,能用 between 就不要用 in 了: 
select id from t where num between 1 and 3 

7.若是在 where 子句中使用參數,也會致使全表掃描。由於SQL只有在運行時纔會解析局部變量,但優化程序不能將訪問計劃的選擇推遲到運行時;它必須在編譯時進行選擇。然而,若是在編譯時創建訪問計劃,變量的值仍是未知的,於是沒法做爲索引選擇的輸入項。以下面語句將進行全表掃描: 
select id from t where num=@num 
能夠改成強制查詢使用索引: 
select id from t with(index(索引名)) where num=@num 

8.應儘可能避免在 where 子句中對字段進行表達式操做,這將致使引擎放棄使用索引而進行全表掃描。如: 
select id from t where num/2=100 
應改成: 
select id from t where num=100*2 

9.應儘可能避免在where子句中對字段進行函數操做,這將致使引擎放棄使用索引而進行全表掃描。如: 
select id from t where substring(name,1,3)='abc'--name以abc開頭的id 
select id from t where datediff(day,createdate,'2005-11-30')=0--'2005-11-30'生成的id 
應改成: 
select id from t where name like 'abc%' 
select id from t where createdate>='2005-11-30' and createdate<'2005-12-1' 

10.不要在 where 子句中的「=」左邊進行函數、算術運算或其餘表達式運算,不然系統將可能沒法正確使用索引。 

11.在使用索引字段做爲條件時,若是該索引是複合索引,那麼必須使用到該索引中的第一個字段做爲條件時才能保證系統使用該索引,不然該索引將不會被使用,而且應儘量的讓字段順序與索引順序相一致。 

12.不要寫一些沒有意義的查詢,如須要生成一個空表結構: 
select col1,col2 into #t from t where 1=0 
這類代碼不會返回任何結果集,可是會消耗系統資源的,應改爲這樣: 
create table #t(...) 

13.不少時候用 exists 代替 in 是一個好的選擇: 
select num from a where num in(select num from b) 
用下面的語句替換: 
select num from a where exists(select 1 from b where num=a.num) 

14.並非全部索引對查詢都有效,SQL是根據表中數據來進行查詢優化的,當索引列有大量數據重複時,SQL查詢可能不會去利用索引,如一表中有字段sex,male、female幾乎各一半,那麼即便在sex上建了索引也對查詢效率起不了做用。 

15.索引並非越多越好,索引當然能夠提升相應的 select 的效率,但同時也下降了 insert 及 update 的效率,由於 insert 或 update 時有可能會重建索引,因此怎樣建索引須要慎重考慮,視具體狀況而定。一個表的索引數最好不要超過6個,若太多則應考慮一些不常使用到的列上建的索引是否有必要。 

16.應儘量的避免更新 clustered 索引數據列,由於 clustered 索引數據列的順序就是表記錄的物理存儲順序,一旦該列值改變將致使整個表記錄的順序的調整,會耗費至關大的資源。若應用系統須要頻繁更新 clustered 索引數據列,那麼須要考慮是否應將該索引建爲 clustered 索引。 

17.儘可能使用數字型字段,若只含數值信息的字段儘可能不要設計爲字符型,這會下降查詢和鏈接的性能,並會增長存儲開銷。這是由於引擎在處理查詢和鏈接時會逐個比較字符串中每個字符,而對於數字型而言只須要比較一次就夠了。 

18.儘量的使用 varchar/nvarchar 代替 char/nchar ,由於首先變長字段存儲空間小,能夠節省存儲空間,其次對於查詢來講,在一個相對較小的字段內搜索效率顯然要高些。 

19.任何地方都不要使用 select * from t ,用具體的字段列表代替「*」,不要返回用不到的任何字段。 

20.儘可能使用表變量來代替臨時表。若是表變量包含大量數據,請注意索引很是有限(只有主鍵索引)。 

21.避免頻繁建立和刪除臨時表,以減小系統表資源的消耗。 

22.臨時表並非不可以使用,適當地使用它們可使某些例程更有效,例如,當須要重複引用大型表或經常使用表中的某個數據集時。可是,對於一次性事件,最好使用導出表。 

23.在新建臨時表時,若是一次性插入數據量很大,那麼可使用 select into 代替 create table,避免形成大量 log ,以提升速度;若是數據量不大,爲了緩和系統表的資源,應先create table,而後insert。 

24.若是使用到了臨時表,在存儲過程的最後務必將全部的臨時表顯式刪除,先 truncate table ,而後 drop table ,這樣能夠避免系統表的較長時間鎖定。 

25.儘可能避免使用遊標,由於遊標的效率較差,若是遊標操做的數據超過1萬行,那麼就應該考慮改寫。 

26.使用基於遊標的方法或臨時表方法以前,應先尋找基於集的解決方案來解決問題,基於集的方法一般更有效。 

27.與臨時表同樣,遊標並非不可以使用。對小型數據集使用 FAST_FORWARD 遊標一般要優於其餘逐行處理方法,尤爲是在必須引用幾個表才能得到所需的數據時。在結果集中包括「合計」的例程一般要比使用遊標執行的速度快。若是開發時間容許,基於遊標的方法和基於集的方法均可以嘗試一下,看哪種方法的效果更好。 

28.在全部的存儲過程和觸發器的開始處設置 SET NOCOUNT ON ,在結束時設置 SET NOCOUNT OFF 。無需在執行存儲過程和觸發器的每一個語句後向客戶端發送 DONE_IN_PROC 消息。 

29.儘可能避免向客戶端返回大數據量,若數據量過大,應該考慮相應需求是否合理。 

30.儘可能避免大事務操做,提升系統併發能力。

 

 

mysql查詢優化以及索引使用

《高性能mysql》

 

若是應用程序使用了MySQL,其中包含一些查詢速度慢的sql,咱們要去優化它們,優化的思路須要如何進行呢?主要是如下兩點:

一、應用程序是否在檢索大量超過須要的數據(行、列);

二、mysql服務器層是否在分析大量超過須要的數據行。

前者比較好進行,主要看開發者的細心以及縝密邏輯、流程分析;後者就須要一些數據庫方面的知識、優化以及實踐技巧。對於後一點,首先須要分清一個概念,就是掃描行數與返回行數的區別,後者是咱們實際取得的數據,而前者是mysql得出後者所須要掃描的數據量。

若是發現查詢大量的數據但只返回少數的行,那麼一般能夠嘗試下面的技巧:一、使用索引覆蓋索引;二、改變庫表結構,如使用單獨的彙總表;三、重寫這個複雜的查詢。

下面針對查詢優化提供一些技巧:

一、分解關聯查詢。

這個主要針對這種查詢:關聯查詢了多個表,這種狀況下可能出現本來能夠經過索引實現的order by失效,數據須要在到達mysql服務器後再進行排序;而且多表關聯,mysql實現的方式是一次掃描取一個表的數據,最後再處理合並,這些都須要消耗mysql的資源。固然,關聯查詢也有一些好處,好比只須要訪問一次mysql,減小網絡請求。當弊大於利時,咱們能夠採起這樣的優化措施,將主表的數據先查詢出來,其餘一些信息,在代碼裏拼湊好條件,一次性查詢出來,再進行屬性合併等操做。

二、當表a和表b用列c關聯,若是優化器的關聯順序是b、a,那麼就不須要在b的對應列上創建索引

三、確保任何group by和order by中的表達式只涉及一個表中的列(最好是優化器掃描的第一個表中的),這樣mysql才能使用索引來優化過程

四、group by表達式,若是沒有顯式的order by表達式,默認會對後面的字段進行排序,若是排序字段沒有用上索引,將是一個很大的性能消耗,尤爲當有聯表時,須要經過臨時表(using temporary)實現。一個優化的技巧,是加上order by null。

四、mysql老是經過建立並填充臨時表的方式來執行union查詢。所以不少優化策略在union查詢中都無法很好地使用,常常須要手工地將where limit order by 等子句"下推"到union的各子查詢中,以便優化器能夠充分利用這些條件進行優化。

除非確實須要服務器消除重複的行,不然就必定要使用union all。緣由是union操做須要取出兩個表的數據,經過排序排除重複的行,會消耗mysql資源,若是數據量大的還要用到磁盤排序。

五、儘可能使用update(經過條件過濾來保證數據一致性等)代替先select for update再update的寫法,由於事務提交的速度越快,持有的鎖時間就越短,能夠大大減小競爭和加速串行執行效率。

六、有些查詢是沒法優化的,能夠考慮使用別的查詢或者策略來實現相同的目的。

七、經過近似計算等方法,先過濾縮小範圍(使用索引),而後再精確過濾。(這種是精確過濾用不上索引時的處理策略)

八、須要的時候,儘量讓程序完成一些計算。(好比結果集中字符串的拼拼湊湊)

 

    在優化查詢的過程當中,索引的創建、使用扮演着很是重要的角色。創建索引時須要全局考慮全部的查詢,而不只僅是當前要處理、優化的查詢,不能由於要優化當前的查詢而嚴重影響其餘查詢的執行效率。創建索引時須要考慮兩點:一、出現頻率高的查詢條件及其順序,二、索引列的選擇性,要講選擇性高的列放到索引的最前列。索引列的選擇性是指:不重複的索引值和數據表的記錄總數的比值,選擇性越高則查詢效率越高。一般主要考慮第一點,由於它對查詢的效率影響較大。

冗餘索引,是指這種狀況,index1(a),index2(a,b),index1是index2的最左前綴,它的做用也就能夠被index2來代替(在使用b-tree索引的時候)。大多數狀況下都不須要冗餘索引,應該儘可能儘可能擴展已有的索引而不是建立新索引。但也有時候處於性能方面的考慮須要冗餘索引,由於擴展已有的索引會致使其變得太大,從而影響其餘使用該索引的查詢性能。

    索引使用中須要注意:

一、只有當索引的列順序和order by子句的順序徹底一致,而且全部列的排序方向(倒序或正序)都同樣時,mysql纔可以使用索引對結果作排序。若是查詢須要關聯多張表,則只有當order by子句引用的字段所有爲第一個表(mysql優化器優化後實際執行時的第一個表)時,才能使用索引作排序。

order by子句和查找型查詢的限制是同樣的,須要知足索引的最左前綴的要求;不然mysql都須要執行排序操做,沒法利用索引排序。有一種狀況,order by子句能夠不知足索引的最左前綴的要求;就是前導列爲常量的時候。若是where子句或者join子句對這些列指定了常量,就能夠彌補索引的不足。

二、對於一個表的一次掃描中最多隻能用到它的一個索引

三、儘可能將須要作範圍查詢的列放到索引的後面,以便優化器可以使用盡量多的索引列

 

 鬆散索引掃描與緊湊索引掃描:

二者的區別:在鬆散索引掃描方式下,分組操做和範圍預測(若是有的話)一塊兒執行完成。在緊湊索引掃描下,先對索引執行範圍掃描(range search),再對結果元組進行分組。

鬆散索引掃描的條件:

1)、查詢在單一表上

2)、group by指定的列是索引的一個最左前綴,而且沒有其餘的列

3)、若是在選擇列表select list中存在聚合函數,只能使用min()和max()兩個聚合函數,而且指定的是同一列

4)、若是查詢中存在除了group by指定的列以外的索引其餘部分,那麼必須以常量的形式出現

5)、索引中的列必須索引整個數據列的值,而不是一個前綴索引(注意不是索引前綴,前綴索引是指索引中的某些列不是某個字段,而是某個字段的前綴部分)

從5.5開始,鬆散索引的掃描條件放寬了:

1)、select中的聚合函數除了min()和max()以外,還支持avg(distinct)、sum(distinct)、count(distinct)

2)、查詢中沒有group by和distinct條件

判斷一個查詢是否使用鬆散索引掃描的方法:執行計劃中有using index for group-by

 

緊湊索引掃描起做用的條件:

在查詢中存在常量相等等where條件字段(索引中的字段),且該字段在group by指定的字段的前面或者中間。來自相等條件的常量可以填充搜索keys中的gaps,於是可以構成一個索引的完整前綴。索引前綴可以用戶索引查找。若是要求對group by的結果進行排序,而且查找字段組成一個索引前綴,那麼mysql一樣能夠避免額外的排序操做。

查詢使用了緊湊索引掃描的判斷方法:執行計劃中有using index

 

 

 

你有90w數據了,這並非由於數據量少而不使用索引,而是你的索引建錯了,沒有任何意義,因此MySQL不會去用你的索引


當你source字段惟一性不高,例如你90w數據,裏面source字段來來去去就那麼十幾個值,這種狀況下影響結果集巨大,就會全表掃描。這種狀況全表掃描還要快於利用索引,只要理解索引的本質不難明白MySQL爲什麼不使用索引。

極端點的狀況,90萬的數據,source只有0和1兩個值,利用索引要先讀索引文件,而後二分查找,找到對應數據的數據磁盤指針,再根據讀到的指針再讀磁盤上對應的數據數據,影響結果集45萬。這種狀況,和直接全表掃描那個快顯而易見。


若是你source字段是一個unique,就會用到索引。

若是你必定要用索引,能夠用force index,不過效率不會有改善通常還會更慢就是了。


合理使用索引,Cardinality是一個重要指標,過小的話跟沒建沒區別,還浪費空間。

相關文章
相關標籤/搜索