1. 程式人生 > 實用技巧 >Python學習第143天(MySQL索引詳解)

Python學習第143天(MySQL索引詳解)

休息了三天,調整了情緒,今天來會看一下mysql部分的內容

MySQL 索引

作用:約束+加速查詢

一.索引分類:

1.普通索引:加速查詢
2.主鍵索引:加速查詢 + 約束(不能為空) + 唯一
3.唯一索引:加速查詢 + 唯一
4.聯合索引(多列)
    - 聯合主鍵索引
    - 聯合唯一索引
    - 聯合普通索引
'''
前三個是單列(欄位)索引
'''

二.索引特點:

無索引:從前到後依次查詢,速度慢,浪費時間

有索引:會建立關聯索引欄位的額外檔案(某種格式),當按該索引欄位查詢資料時,會先到該檔案查詢資料在表的那個位置,再到表中定位到資料

#不同的儲存引擎支援的索引型別也不一樣
InnoDB 支援事務,支援行級別鎖定,支援 B
-tree、Full-text 等索引,不支援 Hash 索引; MyISAM 不支援事務,支援表級別鎖定,支援 B-tree、Full-text 等索引,不支援 Hash 索引; Memory 不支援事務,支援表級別鎖定,支援 B-tree、Hash 等索引,不支援 Full-text 索引; NDB 支援事務,支援行級別鎖定,支援 Hash 索引,不支援 B-tree、Full-text 等索引; Archive 不支援事務,支援表級別鎖定,不支援 B-tree、Hash、Full-text 等索引;

三.索引格式種類

hash索引:會將索引欄位的資料轉換成hash值,每個hash值都綁定了對應資料的儲存地址

缺點:因為hash數值是隨機生成的,導致了存在hash索引表中的資料的無序,所以如果當你要查詢id大於5(範圍)的資料時,就會慢了
優點:找單值速度快

btree索引(******):

如上圖,是一顆b+樹,關於b+樹的定義可以參見B+樹,這裡只說一些重點,淺藍色的塊我們稱之為一個磁碟塊,可以看到每個磁碟塊包含幾個資料項(深藍色所示)和指標(黃色所示),如磁碟塊1包含資料項17和35,包含指標P1、P2、P3,P1表示小於17的磁碟塊,P2表示在17和35之間的磁碟塊,P3表示大於35的磁碟塊。真實的資料存在於葉子節點即3、5、9、10、13、15、28、29、36、60、75、79、90、99。非葉子節點只不儲存真實的資料,只儲存指引搜尋方向的資料項,如17、35並不真實存在於資料表中。

b+樹的查詢過程

如圖所示,如果要查詢資料項29,那麼首先會把磁碟塊1由磁碟載入到記憶體,此時發生一次IO,在記憶體中用二分查詢確定29在17和35之間,鎖定磁碟塊1的P2指標,記憶體時間因為非常短(相比磁碟的IO)可以忽略不計,通過磁碟塊1的P2指標的磁碟地址把磁碟塊3由磁碟載入到記憶體,發生第二次IO,29在26和30之間,鎖定磁碟塊3的P2指標,通過指標載入磁碟塊8到記憶體,發生第三次IO,同時記憶體中做二分查詢找到29,結束查詢,總計三次IO。真實的情況是,3層的b+樹可以表示上百萬的資料,如果上百萬的資料查詢只需要三次IO,效能提高將是巨大的,如果沒有索引,每個資料項都要發生一次IO,那麼總共需要百萬次的IO,顯然成本非常非常高。

b+樹性質

1.索引欄位要儘量的小:通過上面的分析,我們知道IO次數取決於b+數的高度h,假設當前資料表的資料為N,每個磁碟塊的資料項的數量是m,則有h=㏒(m+1)N,當資料量N一定的情況下,m越大,h越小;而m = 磁碟塊的大小 / 資料項的大小,磁碟塊的大小也就是一個數據頁的大小,是固定的,如果資料項佔的空間越小,資料項的數量越多,樹的高度越低。這就是為什麼每個資料項,即索引欄位要儘量的小,比如int佔4位元組,要比bigint8位元組少一半。這也是為什麼b+樹要求把真實的資料放到葉子節點而不是內層節點,一旦放到內層節點,磁碟塊的資料項會大幅度下降,導致樹增高。當資料項等於1時將會退化成線性表。
2.索引的最左匹配特性:當b+樹的資料項是複合的資料結構,比如(name,age,sex)的時候,b+數是按照從左到右的順序來建立搜尋樹的,比如當(張三,20,F)這樣的資料來檢索的時候,b+樹會優先比較name來確定下一步的所搜方向,如果name相同再依次比較age和sex,最後得到檢索的資料;但當(20,F)這樣的沒有name的資料來的時候,b+樹就不知道下一步該查哪個節點,因為建立搜尋樹的時候name就是第一個比較因子,必須要先根據name來搜尋才能知道下一步去哪裡查詢。比如當(張三,F)這樣的資料來檢索時,b+樹可以用name來指定搜尋方向,但下一個欄位age的缺失,所以只能把名字等於張三的資料都找到,然後再匹配性別是F的資料了, 這個是非常重要的性質,即索引的最左匹配特性。

四.建立索引:

優點:查詢速度快(命中索引)

缺點:更新,刪除資料變慢,因為要重新編排索引檔案

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)
)
方式二:
    create index ix_name on 表名(emil);  # 給emil欄位建立索引,取名ix_name
刪除普通索引: 
    drop index ix_name on 表名  
檢視索引:
    show index from table_name;
'''
ps: 建立索引會建立額外的檔案佔用硬碟空間
'''
2.建立唯一索引
方式一:
    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)
)
方式二:
    create unique index 索引名 on 表名(列名)
刪除唯一索引
    drop unique index 索引名 on 表名
3.建立主鍵索引
方式一:
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)
)
​
方式二:
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)
)
方式三:
    alter table 表名 add primary key(列名);
刪除主鍵索引:
    1.alter table 表名 drop primary key;
    2.alter table 表名  modify  列名 int, drop primary key;
4.建立組合索引
方式一:
    create table in3(
    nid int not null auto_increment primary key,
    name varchar(32) not null,
    email varchar(64) not null,
    extra text
)
方式二:
    create index ix_name_email on in3(name,email);
'''
其應用場景為:頻繁的同時使用n列來進行查詢,如:where name = 'xionger' and email = 666@qq.com。
'''
補充:
最左字首匹配:
create index ix_name_email on userinfo(name,email);
​
select * from userinfo where name='xionger';  # 走索引
select * from userinfo where name='xionger' and emil='[email protected]';  # 走索引
select * from userinfo where emil='111@qq,com';  # 不走索引

五.覆蓋索引:

在額外的索引檔案中就把要查詢的資料拿到

例: id為一張表的索引欄位
    select * from userinfo where id = 666;  
    select id from userinfo where id = 666;  # 覆蓋索引

六.合併索引:

把多個單列索引合併著使用

例:id和emil是一張表的兩個單列索引
    select * from userinfo where id = 666 and emil = 111@qq.com;
補充: 
    組合(聯合)索引效率 > 合併索引

七.補充:

全文索引:

會將所有的欄位都生成索引,但在生長的時候不會這麼做,會藉助第三方資料庫操作

正確使用索引(命中索引):

例: id 和 emil 是一張表中的兩個單列索引
- 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 = '[email protected]';
    特別的:當or條件中有未建立索引的列才失效,以下會走索引
            select * from tb1 where nid = 1 or name = 'seven';  # 不走索引
            select * from tb1 where nid = 1 or email = '[email protected]' 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                -- 不使用索引

建立區域性索引

create index ix_name on 表名(欄位(4))  # 其中4表示取該欄位資料的前4個字元做索引
需要用區域性索引的型別:
    text

其他注意

- 避免使用select *
- count(1)或count(列) 代替 count(*)
- 建立表時儘量時 char 代替 varchar
- 表的欄位順序固定長度的欄位優先
- 組合索引代替多個單列索引(經常使用多個條件查詢時)
- 儘量使用短索引
- 使用連線(JOIN)來代替子查詢(Sub-Queries)
- 連表時注意條件型別需一致
- 索引雜湊值(重複少)不適合建索引,例:性別不適合

以上就是全部內容了。