MySQL 進階之索引


一,索引前傳

  在了解數據庫索引之前,首先有必要了解一下數據庫索引的數據結構基礎,那么什么樣的數據結構可以作為索引呢?

  B-tree是最常用的用於索引的數據結構。因為它們是時間復雜度低, 查找、刪除、插入操作都可以可以在對數時間內完成。另外一個重要原因存儲在B-Tree中的數據是有序的。數據庫管理系統(RDBMS)通常決定索引應該用哪些數據結構。但是,在某些情況下,你在創建索引時可以指定索引要使用的數據結構。

       B+是一個樹數據結構,通常用於數據庫和操作系統的文件系統中,B+樹的特點是能夠保持數據穩定有序,其插入與修改擁有比較穩定的對數時間復雜度,B+樹元素自底向上插入,這個和二叉樹剛好相反。

  B+tree 是一個n叉樹,每個節點有多個葉子節點,一顆B+樹包含根節點,內部節點,葉子節點。根節點可能是一個葉子節點,也可能是一個包含兩個或兩個以上葉子節點的節點。

  B+tree的性質:

    1.n棵子tree的節點包含n個關鍵字,不用來保存數據而是保存數據的索引。

    2.所有的葉子結點中包含了全部關鍵字的信息,及指向含這些關鍵字記錄的指針,且葉子結點本身依關鍵字的大小自小而大順序鏈接。

    3.所有的非終端結點可以看成是索引部分,結點中僅含其子樹中的最大(或最小)關鍵字。

        由於B+tree的性質, 它通常被用於數據庫和操作系統的文件系統中。NTFS, ReiserFS, NSS, XFS, JFS, ReFS 和BFS等文件系統都在使用B+樹作為元數據索引,因為B+ 樹的特點是能夠保持數據穩定有序,其插入與修改擁有較穩定的對數時間復雜度(B+ 樹元素自底向上插入)。

B+tree結構原型圖大概如下(引用):

 

 

哈希表索引是怎么工作的?

  哈希表是另外一種你可能看到用作索引的數據結構-這些索引通常被稱為哈希索引。使用哈希索引的原因是,在尋找值時哈希表效率極高。所以,如果使用哈希索引,對於比較字符串是否相等的查詢能夠極快的檢索出的值。

哈希索引的缺點是什么呢?

  哈希表是無順的數據結構,對於很多類型的查詢語句哈希索引都無能為力。舉例來說,假如你想要找出所有小於40歲的員工。你怎么使用使用哈希索引進行查詢?這不可行,因為哈希表只適合查詢鍵值對-也就是說查詢相等的查詢(例:like “WHERE name = ‘Jesus’)。哈希表的鍵值映射也暗示其鍵的存儲是無序的。這就是為什么哈希索引通常不是數據庫索引的默認數據結構-因為在作為索引的數據結構時,其不像B-Tree那么靈活

還有什么其他類型的索引?

  使用R-Tree作為數據結構的索引通常用來為空間問題提供幫助。例如,一個查詢要求“查詢出所有距離我兩公里之內的星巴克”,如果數據庫表使用R- Tree索引,這類查詢的效率將會提高。
  另一種索引是位圖索引(bitmap index), 這類索引適合放在包含布爾值(true 和 false)的列上,但是這些值(表示true或false的值)的許多實例-基本上都是選擇性(selectivity)低的列。

 二,索引內容

2.1、索引
  索引是對數據庫表中一列或者多列的值進行排序的一種結構,使用索引可以快速訪問數據庫表中的特定信息,索引有助於更快的獲取信息。索引是表的目錄,在查找內容之前可以先在目錄中查找索引位置,以此快速定位查詢數據。對於索引,會保存在額外的文件中。

  索引的一個主要的目的就是加快檢索表中數據的方法,也可以協助信息搜尋者能盡快的找到符合限制條件的記錄。

 

2.2、索引種類

      • 普通索引:僅加速查詢
      • 唯一索引:加速查詢 + 列值唯一(可以有null)
        • 唯一索引是不允許其中任何兩行具有相同索引值的索引,當現有數據存在大量的重復的鍵值的時候,大多數數據庫不允許唯一索引與表一起保存,數據庫還可能防止添加將表中創建重復鍵值的新數據。
      • 主鍵索引:加速查詢 + 列值唯一 + 表中只有一個(不可以有null)
        • 數據庫表經常有一列或者多列組合,其值唯一標識表中的每一行,每一列稱為表的主鍵,在數據庫關系圖中為表定義主鍵將自動創建主鍵索引,主鍵索引是唯一索引的特定類型,該索引要求主鍵索引的每個值都唯一。
      • 組合索引:多列值組成一個索引,
                      專門用於組合搜索,其效率大於索引合並
      • 全文索引:對文本的內容進行分詞,進行搜索 

——普通索引

 -1,創建表 + 索引

create table in1(
    nid int not null auto_increment primary key,
    name varchar(32) not null,
    email varchar(64) not null,
    extra text,
    index ix_name (name)
)

 -2,創建表

create index index_name on table_name(column_name)

-3,刪除表

drop index_name on table_name;

-4,查看索引

show index from table_name;

 注意:對於創建索引時如果是BLOB 和 TEXT 類型,必須指定length。

create index ix_extra on in1(extra(32));

——唯一索引

-1,創建表 + 唯一索引

create table in1(
    nid int not null auto_increment primary key,
    name varchar(32) not null,
    email varchar(64) not null,
    extra text,
    unique ix_name (name)
)

-2,創建唯一索引

create unique index 索引名 on 表名(列名)

-3,刪除唯一索引

drop unique index 索引名 on 表名

——主鍵索引

-1,創建表+創建主鍵

create table in1(
    nid int not null auto_increment primary key,
    name varchar(32) not null,
    email varchar(64) not null,
    extra text,
    index ix_name (name)
)

OR

create table in1(
    nid int not null auto_increment,
    name varchar(32) not null,
    email varchar(64) not null,
    extra text,
    primary key(ni1),
    index ix_name (name)
)

-2,創建主鍵

alter table 表名 add primary key(列名);

-3,刪除主鍵

alter table 表名 drop primary key;
alter table 表名  modify  列名 int, drop primary key;

——組合索引

組合索引是將n個列組合成一個索引

其應用場景為:頻繁的同時使用n列來進行查詢,如:where n1 = 'alex' and n2 = 666。

-1,創建表

create table in3(
    nid int not null auto_increment primary key,
    name varchar(32) not null,
    email varchar(64) not null,
    extra text
)

-2,創建組合索引

create index ix_name_email on in3(name,email);

如上創建組合索引之后,查詢:

  • name and email  -- 使用索引
  • name                 -- 使用索引
  • email                 -- 不使用索引

注意:對於同時搜索n個條件時,組合索引的性能好於多個單一索引合並。

 ——其他

-1,條件語句(if條件語句例子)

delimiter \\
CREATE PROCEDURE proc_if ()
BEGIN
    
    declare i int default 0;
    if i = 1 THEN
        SELECT 1;
    ELSEIF i = 2 THEN
        SELECT 2;
    ELSE
        SELECT 7;
    END IF;

END\\
delimiter ;

-2,while循環語句

delimiter \\
CREATE PROCEDURE proc_while ()
BEGIN

    DECLARE num INT ;
    SET num = 0 ;
    WHILE num < 10 DO
        SELECT
            num ;
        SET num = num + 1 ;
    END WHILE ;

END\\
delimiter ;

 

-3,repeat循環語句

delimiter \\
CREATE PROCEDURE proc_repeat ()
BEGIN

    DECLARE i INT ;
    SET i = 0 ;
    repeat
        select i;
        set i = i + 1;
        until i >= 5
    end repeat;

END\\
delimiter ;

  

-4,loop循環語句

BEGIN
    
    declare i int default 0;
    loop_label: loop
        
        set i=i+1;
        if i<8 then
            iterate loop_label;
        end if;
        if i>=10 then
            leave loop_label;
        end if;
        select i;
    end loop loop_label;

END

  

-5,動態執行SQL語句

delimiter \\
DROP PROCEDURE IF EXISTS proc_sql \\
CREATE PROCEDURE proc_sql ()
BEGIN
    declare p1 int;
    set p1 = 11;
    set @p1 = p1;

    PREPARE prod FROM 'select * from tb2 where nid > ?';
    EXECUTE prod USING @p1;
    DEALLOCATE prepare prod; 

END\\
delimiter ;

 

2.3、相關命令

查看表結構
    desc 表名
 
- 查看生成表的SQL
    show create table 表名
 
- 查看索引
    show index from  表名
 
- 查看執行時間
    set profiling = 1;
    SQL...
    show profiles;

2.4、索引的優缺點(使用索引和不使用索引)

 

通過建立索引可以極大地提高在數據庫中獲取所需信息的速度,同時還能提高服務器處理相關搜索請求的效率,從這個方面來看它具有以下優點:

 

  • 在設計數據庫時,通過創建一個惟一的索引,能夠在索引和信息之間形成一對一的映射式的對應關系,增加數據的惟一性特點。
  • 能提高數據的搜索及檢索速度,符合數據庫建立的初衷。
  • 能夠加快表與表之間的連接速度,這對於提高數據的參考完整性方面具有重要作用。
  • 在信息檢索過程中,若使用分組及排序子句進行時,通過建立索引能有效的減少檢索過程中所需的分組及排序時間,提高檢索效率。
  • 建立索引之后,在信息查詢過程中可以使用優化隱藏器,這對於提高整個信息檢索系統的性能具有重要意義。
雖然索引的建立在提高檢索效率方面具有諸多積極的作用,但還是存在下列缺點  :
  • 在數據庫建立過程中,需花費較多的時間去建立並維護索引,特別是隨着數據總量的增加,所花費的時間將不斷遞增。
  • 在數據庫中創建的索引需要占用一定的物理存儲空間,這其中就包括數據表所占的數據空間以及所創建的每一個索引所占用的物理空間,如果有必要建立起聚簇索引,所占用的空間還將進一步的增加
  • 在對表中的數據進行修改時,例如對其進行增加、刪除或者是修改操作時,索引還需要進行動態的維護,這給數據庫的維護速度帶來了一定的麻煩。

 

由於索引是專門用於加速搜索而生,所以加上索引之后,查詢效率會快到飛起來。
 
# 有索引
mysql> select * from tb1 where name = 'wupeiqi-888';
+-----+-------------+---------------------+----------------------------------+---------------------+
| nid | name        | email               | radom                            | ctime               |
+-----+-------------+---------------------+----------------------------------+---------------------+
| 255 | tonm        | 12474565666@qq.com  | cdccccce76a16a90b8a8301d5314204b | 2017-08-03 09:33:35 |
+-----+-------------+---------------------+----------------------------------+---------------------+
1 row in set (0.00 sec)
 
# 無索引
mysql> select * from tb1 where email = 'wupeiqi888@live.com';
+-----+-------------+---------------------+----------------------------------+---------------------+
| nid | name        | email               | radom                            | ctime               |
+-----+-------------+---------------------+----------------------------------+---------------------+
| 256 | tonm        | 12474565666@qq.com  | 5312269e76a1clslclscc01d5314204b | 2017-08-03 09:33:35 |
+-----+-------------+---------------------+----------------------------------+---------------------+
1 row in set (1.23 sec)

  

25、正確使用索引

數據庫表中添加索引后確實會讓查詢速度起飛,但前提必須是正確的使用索引來查詢,如果以錯誤的方式使用,則即使建立索引也會不奏效。
即使建立索引,索引也不會生效:

- like '%xx'
    select * from tb1 where name like '%cn';
- 使用函數
    select * from tb1 where reverse(name) = 'wupeiqi';
- or
    select * from tb1 where nid = 1 or email = 'seven@live.com';
    特別的:當or條件中有未建立索引的列才失效,以下會走索引
            select * from tb1 where nid = 1 or name = 'seven';
            select * from tb1 where nid = 1 or email = 'seven@live.com' and name = 'alex'
- 類型不一致
    如果列是字符串類型,傳入條件是必須用引號引起來,不然...
    select * from tb1 where name = 999;
- !=
    select * from tb1 where name != 'alex'
    特別的:如果是主鍵,則還是會走索引
        select * from tb1 where nid != 123
- >
    select * from tb1 where name > 'alex'
    特別的:如果是主鍵或索引是整數類型,則還是會走索引
        select * from tb1 where nid > 123
        select * from tb1 where num > 123
- order by
    select email from tb1 order by name desc;
    當根據索引排序時候,選擇的映射如果不是索引,則不走索引
    特別的:如果對主鍵排序,則還是走索引:
        select * from tb1 order by nid desc;
 
- 組合索引最左前綴
    如果組合索引為:(name,email)
    name and email       -- 使用索引
    name                 -- 使用索引
    email                -- 不使用索引

 

2.6,使用索引注意事項

   索引是建立在數據庫表中的某些列的上面。在創建索引的時候,應該考慮在哪些列上可以創建索引,在哪些列上不能創建索引。一般來說,應該在這些列上創建索引:
  在經常需要搜索的列上,可以加快搜索的速度;
  在作為 主鍵的列上,強制該列的唯一性和組織表中數據的排列結構;
  在經常用在連接的列上,這些列主要是一些 外鍵,可以加快連接的速度;在經常需要根據范圍進行搜索的列上創建索引,因為索引已經排序,其指定的范圍是連續的;
  在經常需要排序的列上創建索引,因為索引已經排序,這樣查詢可以利用索引的排序,加快排序查詢時間;
  在經常使用在WHERE子句中的列上面創建 索引,加快條件的判斷速度。
  同樣,對於有些列不應該創建索引。一般來說,不應該創建索引的這些列具有下列特點:
  第一,對於那些在查詢中很少使用或者參考的列不應該創建索引。這是因為,既然這些列很少使用到,因此有索引或者無索引,並不能提高查詢速度。相反,由於增加了索引,反而降低了系統的維護速度和增大了空間需求。
  第二,對於那些只有很少數據值的列也不應該增加索引。這是因為,由於這些列的取值很少,例如人事表的性別列,在查詢的結果中, 結果集的數據行占了表中數據行的很大比例,即需要在表中搜索的數據行的比例很大。增加 索引,並不能明顯加快檢索速度。
  第三,對於那些定義為text, image和 bit數據類型的列不應該增加索引。這是因為,這些列的數據量要么相當大,要么取值很少,不利於使用索引。
  第四,當修改性能遠遠大於檢索性能時,不應該創建索引。這是因為,修改性能和檢索性能是互相矛盾的。當增加索引時,會提高檢索性能,但是會降低修改性能。當減少索引時,會提高修改性能,降低檢索性能。因此,當修改操作遠遠多於檢索操作時,不應該創建索引。

 三,索引后記

3.1把數據庫索引類比成什么比較好呢?

  一個非常好的類比是把數據庫索引看作是書的索引。如果你有一本關於狗的書,你想要找關於‘黃金獵犬’的那部分。當你可以通過在書背的索引找到哪幾頁有關於‘黃金獵犬’信息的時候,你為什么要翻完正本書 - 這相當於數據庫中的全表掃描。同樣的,就像一本書的索引包含頁碼一樣,數據庫的索引包含了指針,指向你在SQL中想要查詢的值所在的行。

3.2使用數據庫索引會有什么代價?

  那么,使用數據庫索引有什么缺點呢?其一,索引會占用空間 - 你的表越大,索引占用的空間越大。其二,性能損失(主要值更新操作),當你在表中添加、刪除或者更新行數據的時候, 在索引中也會有相同的操作。

記住:建立在某列(或多列)索引需要保存該列最新的數據

基本原則是只如果表中某列在查詢過程中使用的非常頻繁,那就在該列上創建索引

3.3、limit分頁

無論是否有索引,limit分頁是一個值得關注的問題

每頁顯示10條:
當前 118 120, 125

倒序:
            大      小
   970  7 6  6 5  54  43  32
19 98     
下一頁:

    select 
        * 
    from 
        tb1 
    where 
        nid < (select nid from (select nid from tb1 where nid < 當前頁最小值 order by nid desc limit 每頁數據 *【頁碼-當前頁】) A order by A.nid asc limit 1)  
    order by 
        nid desc 
    limit 10;



    select 
        * 
    from 
        tb1 
    where 
        nid < (select nid from (select nid from tb1 where nid < 970  order by nid desc limit 40) A order by A.nid asc limit 1)  
    order by 
        nid desc 
    limit 10;


上一頁:

    select 
        * 
    from 
        tb1 
    where 
        nid < (select nid from (select nid from tb1 where nid > 當前頁最大值 order by nid asc limit 每頁數據 *【當前頁-頁碼】) A order by A.nid asc limit 1)  
    order by 
        nid desc 
    limit 10;


    select 
        * 
    from 
        tb1 
    where 
        nid < (select nid from (select nid from tb1 where nid > 980 order by nid asc limit 20) A order by A.nid desc limit 1)  
    order by 
        nid desc 
    limit 10;

  

3.4、執行計划

explain + 查詢SQL - 用於顯示SQL執行信息參數,根據參考信息可以進行SQL優化

mysql> explain select * from tb2;
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
|  1 | SIMPLE      | tb2   | ALL  | NULL          | NULL | NULL    | NULL |    2 | NULL  |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
1 row in set (0.00 sec)
id
        查詢順序標識
            如:mysql> explain select * from (select nid,name from tb1 where nid < 10) as B;
            +----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
            | id | select_type | table      | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
            +----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
            |  1 | PRIMARY     | <derived2> | ALL   | NULL          | NULL    | NULL    | NULL |    9 | NULL        |
            |  2 | DERIVED     | tb1        | range | PRIMARY       | PRIMARY | 8       | NULL |    9 | Using where |
            +----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
        特別的:如果使用union連接氣值可能為null


    select_type
        查詢類型
            SIMPLE          簡單查詢
            PRIMARY         最外層查詢
            SUBQUERY        映射為子查詢
            DERIVED         子查詢
            UNION           聯合
            UNION RESULT    使用聯合的結果
            ...
    table
        正在訪問的表名


    type
        查詢時的訪問方式,性能:all < index < range < index_merge < ref_or_null < ref < eq_ref < system/const
            ALL             全表掃描,對於數據表從頭到尾找一遍
                            select * from tb1;
                            特別的:如果有limit限制,則找到之后就不在繼續向下掃描
                                   select * from tb1 where email = 'seven@live.com'
                                   select * from tb1 where email = 'seven@live.com' limit 1;
                                   雖然上述兩個語句都會進行全表掃描,第二句使用了limit,則找到一個后就不再繼續掃描。

            INDEX           全索引掃描,對索引從頭到尾找一遍
                            select nid from tb1;

            RANGE          對索引列進行范圍查找
                            select *  from tb1 where name < 'alex';
                            PS:
                                between and
                                in
                                >   >=  <   <=  操作
                                注意:!= 和 > 符號


            INDEX_MERGE     合並索引,使用多個單列索引搜索
                            select *  from tb1 where name = 'alex' or nid in (11,22,33);

            REF             根據索引查找一個或多個值
                            select *  from tb1 where name = 'seven';

            EQ_REF          連接時使用primary key 或 unique類型
                            select tb2.nid,tb1.name from tb2 left join tb1 on tb2.nid = tb1.nid;



            CONST           常量
                            表最多有一個匹配行,因為僅有一行,在這行的列值可被優化器剩余部分認為是常數,const表很快,因為它們只讀取一次。
                            select nid from tb1 where nid = 2 ;

            SYSTEM          系統
                            表僅有一行(=系統表)。這是const聯接類型的一個特例。
                            select * from (select nid from tb1 where nid = 1) as A;
    possible_keys
        可能使用的索引

    key
        真實使用的

    key_len
        MySQL中使用索引字節長度

    rows
        mysql估計為了找到所需的行而要讀取的行數 ------ 只是預估值

    extra
        該列包含MySQL解決查詢的詳細信息
        “Using index”
            此值表示mysql將使用覆蓋索引,以避免訪問表。不要把覆蓋索引和index訪問類型弄混了。
        “Using where”
            這意味着mysql服務器將在存儲引擎檢索行后再進行過濾,許多where條件里涉及索引中的列,當(並且如果)它讀取索引時,就能被存儲引擎檢驗,因此不是所有帶where子句的查詢都會顯示“Using where”。有時“Using where”的出現就是一個暗示:查詢可受益於不同的索引。
        “Using temporary”
            這意味着mysql在對查詢結果排序時會使用一個臨時表。
        “Using filesort”
            這意味着mysql會對結果使用一個外部索引排序,而不是按索引次序從表里讀取行。mysql有兩種文件排序算法,這兩種排序方式都可以在內存或者磁盤上完成,explain不會告訴你mysql將使用哪一種文件排序,也不會告訴你排序會在內存里還是磁盤上完成。
        “Range checked for each record(index map: N)”
            這個意味着沒有好用的索引,新的索引將在聯接的每一行上重新估算,N是顯示在possible_keys列中索引的位圖,並且是冗余的。

詳細

  

1)、id列數字越大越先執行,如果說數字一樣大,那么就從上往下依次執行,id列為null的就表是這是一個結果集,不需要使用它來進行查詢。

 
2)、select_type列常見的有:
A:simple:表示不需要union操作或者不包含子查詢的簡單select查詢。有連接查詢時,外層的查詢為simple,且只有一個
B:primary:一個需要union操作或者含有子查詢的select,位於最外層的單位查詢的select_type即為primary。且只有一個
C:union:union連接的兩個select查詢,第一個查詢是dervied派生表,除了第一個表外,第二個以后的表select_type都是union
D:dependent union:與union一樣,出現在union 或union all語句中,但是這個查詢要受到外部查詢的影響
E:union result:包含union的結果集,在union和union all語句中,因為它不需要參與查詢,所以id字段為null
F:subquery:除了from字句中包含的子查詢外,其他地方出現的子查詢都可能是subquery
G:dependent subquery:與dependent union類似,表示這個subquery的查詢要受到外部表查詢的影響
H:derived:from字句中出現的子查詢,也叫做派生表,其他數據庫中可能叫做內聯視圖或嵌套select
 
3)、table
顯示的查詢表名,如果查詢使用了別名,那么這里顯示的是別名,如果不涉及對數據表的操作,那么這顯示為null,如果顯示為尖括號括起來的<derived N>就表示這個是臨時表,后邊的N就是執行計划中的id,表示結果來自於這個查詢產生。如果是尖括號括起來的<union M,N>,與<derived N>類似,也是一個臨時表,表示這個結果來自於union查詢的id為M,N的結果集。
 
4)、type
依次從好到差:system,const,eq_ref,ref,fulltext,ref_or_null,unique_subquery,index_subquery,range,index_merge,index,ALL,除了all之外,其他的type都可以使用到索引,除了index_merge之外,其他的type只可以用到一個索引
A:system:表中只有一行數據或者是空表,且只能用於myisam和memory表。如果是Innodb引擎表,type列在這個情況通常都是all或者index
B:const:使用唯一索引或者主鍵,返回記錄一定是1行記錄的等值where條件時,通常type是const。其他數據庫也叫做唯一索引掃描
C:eq_ref:出現在要連接過個表的查詢計划中,驅動表只返回一行數據,且這行數據是第二個表的主鍵或者唯一索引,且必須為not null,唯一索引和主鍵是多列時,只有所有的列都用作比較時才會出現eq_ref
D:ref:不像eq_ref那樣要求連接順序,也沒有主鍵和唯一索引的要求,只要使用相等條件檢索時就可能出現,常見與輔助索引的等值查找。或者多列主鍵、唯一索引中,使用第一個列之外的列作為等值查找也會出現,總之,返回數據不唯一的等值查找就可能出現。
E:fulltext:全文索引檢索,要注意,全文索引的優先級很高,若全文索引和普通索引同時存在時,mysql不管代價,優先選擇使用全文索引
F:ref_or_null:與ref方法類似,只是增加了null值的比較。實際用的不多。
G:unique_subquery:用於where中的in形式子查詢,子查詢返回不重復值唯一值
H:index_subquery:用於in形式子查詢使用到了輔助索引或者in常數列表,子查詢可能返回重復值,可以使用索引將子查詢去重。
I:range:索引范圍掃描,常見於使用>,<,is null,between ,in ,like等運算符的查詢中。
J:index_merge:表示查詢使用了兩個以上的索引,最后取交集或者並集,常見and ,or的條件使用了不同的索引,官方排序這個在ref_or_null之后,但是實際上由於要讀取所個索引,性能可能大部分時間都不如range
K:index:索引全表掃描,把索引從頭到尾掃一遍,常見於使用索引列就可以處理不需要讀取數據文件的查詢、可以使用索引排序或者分組的查詢。
L:all:這個就是全表掃描數據文件,然后再在server層進行過濾返回符合要求的記錄。
 
5)、possible_keys
查詢可能使用到的索引都會在這里列出來
 
6)、key
查詢真正使用到的索引,select_type為index_merge時,這里可能出現兩個以上的索引,其他的select_type這里只會出現一個。
 
7)、key_len
用於處理查詢的索引長度,如果是單列索引,那就整個索引長度算進去,如果是多列索引,那么查詢不一定都能使用到所有的列,具體使用到了多少個列的索引,這里就會計算進去,沒有使用到的列,這里不會計算進去。留意下這個列的值,算一下你的多列索引總長度就知道有沒有使用到所有的列了。要注意,mysql的ICP特性使用到的索引不會計入其中。另外, key_len只計算where條件用到的索引長度,而排序和分組就算用到了索引,也不會計算到key_len中。
 
8)、ref
如果是使用的常數等值查詢,這里會顯示const,如果是連接查詢,被驅動表的執行計划這里會顯示驅動表的關聯字段,如果是條件使用了表達式或者函數,或者條件列發生了內部隱式轉換,這里可能顯示為func
 
9)、rows
這里是執行計划中估算的掃描行數,不是精確值
 
10)、extra
這個列可以顯示的信息非常多,有幾十種,常用的有
A:distinct:在select部分使用了distinc關鍵字
B:no tables used:不帶from字句的查詢或者From dual查詢
C:使用not in()形式子查詢或not exists運算符的連接查詢,這種叫做反連接。即,一般連接查詢是先查詢內表,再查詢外表,反連接就是先查詢外表,再查詢內表。
D:using filesort:排序時無法使用到索引時,就會出現這個。常見於order by和group by語句中
E:using index:查詢時不需要回表查詢,直接通過索引就可以獲取查詢的數據。
F:using join buffer(block nested loop),using join buffer(batched key accss):5.6.x之后的版本優化關聯查詢的BNL,BKA特性。主要是減少內表的循環數量以及比較順序地掃描查詢。
G:using sort_union,using_union,using intersect,using sort_intersection:
using intersect:表示使用and的各個索引的條件時,該信息表示是從處理結果獲取交集
using union:表示使用or連接各個使用索引的條件時,該信息表示從處理結果獲取並集
using sort_union和using sort_intersection:與前面兩個對應的類似,只是他們是出現在用and和or查詢信息量大時,先查詢主鍵,然后進行排序合並后,才能讀取記錄並返回。
H:using temporary:表示使用了臨時表存儲中間結果。臨時表可以是內存臨時表和磁盤臨時表,執行計划中看不出來,需要查看status變量,used_tmp_table,used_tmp_disk_table才能看出來。
I:using where:表示存儲引擎返回的記錄並不是所有的都滿足查詢條件,需要在server層進行過濾。查詢條件中分為限制條件和檢查條件,5.6之前,存儲引擎只能根據限制條件掃描數據並返回,然后server層根據檢查條件進行過濾再返回真正符合查詢的數據。5.6.x之后支持ICP特性,可以把檢查條件也下推到存儲引擎層,不符合檢查條件和限制條件的數據,直接不讀取,這樣就大大減少了存儲引擎掃描的記錄數量。extra列顯示using index condition
J:firstmatch(tb_name):5.6.x開始引入的優化子查詢的新特性之一,常見於where字句含有in()類型的子查詢。如果內表的數據量比較大,就可能出現這個
K:loosescan(m..n):5.6.x之后引入的優化子查詢的新特性之一,在in()類型的子查詢中,子查詢返回的可能有重復記錄時,就可能出現這個
 
除了這些之外,還有很多查詢數據字典庫,執行計划過程中就發現不可能存在結果的一些提示信息
 
11)、filtered
使用explain extended時會出現這個列,5.7之后的版本默認就有這個字段,不需要使用explain extended了。這個字段表示存儲引擎返回的數據在server層過濾后,剩下多少滿足查詢的記錄數量的比例,注意是百分比,不是具體記錄數。

3.5、慢日志查詢

a、配置MySQL自動記錄慢日志

slow_query_log = OFF                            是否開啟慢日志記錄
long_query_time = 2                              時間限制,超過此時間,則記錄
slow_query_log_file = /usr/slow.log        日志文件
log_queries_not_using_indexes = OFF     為使用索引的搜索是否記錄

注:查看當前配置信息:
       show variables like '%query%'
     修改當前配置:
    set global 變量名 = 值

b、查看MySQL慢日志

mysqldumpslow -s at -a  /usr/local/var/mysql/MacBook-Pro-3-slow.log

"""
--verbose    版本
--debug      調試
--help       幫助
 
-v           版本
-d           調試模式
-s ORDER     排序方式
             what to sort by (al, at, ar, c, l, r, t), 'at' is default
              al: average lock time
              ar: average rows sent
              at: average query time
               c: count
               l: lock time
               r: rows sent
               t: query time
-r           反轉順序,默認文件倒序拍。reverse the sort order (largest last instead of first)
-t NUM       顯示前N條just show the top n queries
-a           不要將SQL中數字轉換成N,字符串轉換成S。don't abstract all numbers to N and strings to 'S'
-n NUM       abstract numbers with at least n digits within names
-g PATTERN   正則匹配;grep: only consider stmts that include this string
-h HOSTNAME  mysql機器名或者IP;hostname of db server for *-slow.log filename (can be wildcard),
             default is '*', i.e. match all
-i NAME      name of server instance (if using mysql.server startup script)
-l           總時間中不減去鎖定時間;don't subtract lock time from total time
"""

  

 

數據庫的索引非常重要,基本面試數據庫的問題都在索引上,所以這里小編整理出來,一方面為了自己復習,一方面也方便大家。

(關於MySQL的安裝,具體見下面博客:http://www.cnblogs.com/wj-1314/p/7573242.html

(關於MySQL的基礎知識,具體見下面博客:http://www.cnblogs.com/wj-1314/p/8343101.html

(關於MySQL的筆試知識,具體見下面博客:http://www.cnblogs.com/wj-1314/p/7643125.html

 此篇博客主要參考:http://www.cnblogs.com/wupeiqi/articles/5716963.html;http://www.cnblogs.com/xiaoboluo768/p/5400990.html,寫在這里主要是為了鞏固學習知識,同時希望更多的同學學習。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM