阿里的御用框架,MyBatis與設計模式的激情碰撞
MySQL索引
-
定義
- 是資料庫管理系統中的一個排序資料結構,佔用一定的儲存空間,底層實現B樹
-
索引解決了什麼問題
- 資料表做資料查詢一般情況是全表掃描,資料量小的話,一千以下,時間消耗不大,如果資料量超過一千以上,效率開始以每千條增加1.3ms。索引可以極大地提高查詢效率,將查詢效能提升幾個數量級。索引原理:對資料分門別類縮小查詢範圍從而提高查詢效率。
-
MySQL索引種類:主要有五種
- 主鍵索引(primary key)
- 特殊的唯一索引:唯一索引=主鍵索引+null 值
- 列的值必須唯一,不允許有重複值,不允許有空值
- 可以再建立表的時候直接指定,不能使用create index 建立,可以使用alter table 建立
- 唯一索引(unique )
- 與普通索引類似
- 不同的是索引的列值必須是唯一的,不能有重複值
- 列值可以允許有空值
- 如果是組合索引,列值的組合必須是唯一的
- 普通索引
- 最基本的索引,沒有任何限制
- 組合索引
- 普通索引+多列
- 全文索引(fulltext index)
- 全文FullText索引用於全文搜尋,只有InnoDB和MyiSAM儲存引擎支援全文索引
- 僅適用於char、varchar、text列
- 主鍵索引(primary key)
-
關於索引的幾個問題
-
建立索引的表的資料量需要有多大?
-
資料量超過一千條,才會看出索引效率
-
region 是資料量為三千七條的表,bs_street 表資料四萬二
-
select * from region where id = ‘310112’;–有索引時: 0.001s
select * from bs_street where street_id = ‘65537’; ## 有索引:0.001s 精準查詢+索引 select * from bs_street where street_id = ‘65537’; 沒有索引時:0.053s
結論:每千條資料增加查詢時間1.3ms
-
-
表建立時預設為主鍵建立索引?
- 不是,只有使用primary key 定義了主鍵id,才會在主鍵id上建立索引primary key
-
在sql中建立sql語句驗證sql執行效率?
- 示列:name建立一個普通索引
- alter table region add index name_index(name);
- select * from region where name = ‘閔行區’;-- 0.001s
- 查詢效率一下子就提高了:-- 0.004s
- 示列:name建立一個普通索引
-
建立專案驗證sql查詢效率?
- 有業務邏輯程式碼佔用時間,
- 對於表的操作增刪改查,是否擁有索引,效率檢視,直接在sql語句的執行時間就可以了
-
同一列上是否可以新增多種索引?
-
alter table region add primary key (id) ; alter table region add unique (id) ; alter table region add index id_index (id);
-
上述sql執行成功,同一列上可以新增多種索引。
-
-
如果某列上有多個索引,查詢效果會疊加嗎?
- 不會,因為每條sql的查詢只能使用一個索引
- explain select * from region where id = ‘110115’
- id是主鍵索引、唯一索引、普通索引、生效的只有primary key
-
查詢中如果多個語句分別用到了索引,查詢的效率是否疊加?
- select * from region where id = (select id from region where name = ‘大興區’);–id無索引,name無索引,0.011s
- select * from region where id = (select id from region where name = ‘大興區’);–id有索引,name無索引,0.004s
- select * from region where id = (select id from region where name = ‘大興區’);–id有索引,name有索引,0.001s
- id 列是primary key 索引,name列是index 普通索引
- 查詢中每個都用到了單列索引,查詢的效率肯定是疊加的。
-
-
如何使用索引
-
建立索引
-
CREATE INDEX INDEX_NAME ON TABLE_NAME (COLUMN)
-
不適用於主鍵索引primary key
示例:create index name_index on region (name) ;
-
-
建立表時建立索引
-
create table teacher( id int(10) not null , name varchar(20) null, age int(3) null, address varchar(30) null, primary key (id) )
-
-
-
檢視索引
-
show index from table_name ;
示例:show index from region ;
-
show keys from table_name ;
-
-
修改表結構時新增索引
1.新增PRIMARY KEY(主鍵索引)
ALTER TABLE
table_name
ADD PRIMARY KEY (column
) 2.新增UNIQUE(唯一索引)
ALTER TABLEtable_name
ADD UNIQUE (column
) 3.新增INDEX(普通索引)
ALTER TABLE
table_name
ADD INDEX index_name (column
) 4.新增FULLTEXT(全文索引)
ALTER TABLE
table_name
ADD FULLTEXT (column
) 5.新增多列索引
ALTER TABLE
table_name
ADD INDEX index_name (column1
,column2
,column3
) 組合索引和普通索引,因為不是唯一的,所以需要指定索引名
主鍵索引、唯一索引、全文索引,因為是唯一的,所以只需要指定索引型別就可以了
-
刪除索引
-
drop index index_name on table_name ;
- 示例:DROP INDEX NAME_INDEX ON REGION ;
-
alter table table_name drop index index_name ;
-
alter table table_name drop primary key ;
- 示例:alter table region drop primary key ;
-
[SQL]alter table region drop primary key ;
受影響的行: 3750 時間: 4.576s -
索引已經刪除了,再執行一次:alter table region drop primary key ;
[SQL]alter table region drop primary key ;
[Err] 1091 - Can’t DROP ‘PRIMARY’; check that column/key exists
-
-
驗證索引是否生效
- explain select * from region where id = ‘110115’ and name = ‘大興區’;
- 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子句限制搜尋結果集。
- explain select * from region where id = ‘110115’ and name = ‘大興區’;
-
主鍵索引
-
定義
- 如果該列的特點是:值唯一,無null值,可以使用primary key 來約束和保證。
- 每張表中只能由一個primary key 主鍵索引,如果在不同的列上重複定義primary,報錯:[Err] 1068 - Multiple primary key defined
-
解決了什麼問題
- 作為索引,提高了查詢效率
- 保證了列值唯一,不能有重複值、不能有null值
-
如何使用
-
檢視索引
show index from region ;
-
建立索引
create primary key on region (id) ; – 無效
-
新增索引
alter table region add primary key (id) ;-- 3.594s
-
刪除索引
drop primary key on region ;## 無效
alter table region drop primary key ; – 3.726s -
驗證索引是否生效
select * from region where id = ‘810305’ ; ## 有索引時:0.001s 無索引時: 0.006s
explain select * from region where id = ‘810305’ ; -
同一張表中分別定義不同的列為primary key ,
- alter table region add primary key (id) ;
- alter table region add primary key (Lng) ;
- 報錯:[Err] 1068 - Multiple primary key defined
-
-
-
唯一索引
- 定義
- 它與前面的"主鍵索引"類似,不同的就是:唯一索引列的值必須唯一,但允許有空值。如果是組合索引,則列值的組合必須唯一
- 為什麼使用唯一索引
- 提高查詢效率
- 保證列值的唯一性,可以有null值
- 參考別人的解釋:你為了做到資料不能有重複值,但是資料庫怎麼保證沒有重複值呢?當然是在儲存資料的時候查一遍,那麼怎樣查詢快呢? 當然是建立索引
- 如何使用唯一索引
- 唯一索引
show index from region ; - 建立唯一索引
create unique index np_u_index on region (name,pid); - 新增索引 (可以根據多列值建立唯一索引)
alter table region add unique index np_u_index (name,pid) ; - 檢視索引
show index from region ; - 刪除索引
alter table region drop index np_u_index ;
drop index np_u_index on region ; - 驗證索引是否生效
select * from region where name = ‘大堂區’ and pid = ‘820100’ ; ## 有索引時:0.002s 無索引時: 0.005s
explain select * from region where name = ‘大堂區’ and pid = ‘820100’ ;
- 唯一索引
- 定義
-
普通索引
- 定義
- 沒有約束,可以用於任何列,允許null值,允許重複值
- 解決了什麼問題
- 提高列值作為查詢條件時的查詢效率
- 如何使用
- 建立索引
create index name_index on region(name) ; - 檢視索引
show index from region ; - 新增索引
alter table region add index name_index (name) ; - 刪除索引
drop index name_index on region
alter table region drop index name_index ;
select * from region where name = ‘大堂區’ ; ## 有索引時:0.001s 無索引時: 0.005s
explain select * from region where name = ‘大堂區’ ;
- 建立索引
- 定義
-
複合索引
-
定義
- 在多列上建立的普通索引叫做複合索引
- 複合索引查詢效率由高到低,從左往右排列,類似於:省市區街道戶
- 遵循最左原則,
- 複合索引所在的列不能有null值,如果某列中有null值,該列索引無效
- 例如索引是key index (a,b,c). 可以支援a | a,b| a,b,c 3種組合進行查詢,但不支援 b,c進行查詢 .當最左側欄位是常量引用時,索引就十分有效。
-
解決了什麼問題
- 複合索引在資料庫操作間佔用的開銷更小,可以代替多個單一索引
- 有兩個概念:窄索引和款索引,窄索引:指索引列為1-2列的索引
- 寬索引:指索引列超過2列的索引
- 設計索引的一個重要原則:儘量使用窄索引不用寬索引,因為窄索引更加高效
-
如何使用
-
建立索引
create index name_pid_yzcode on region (name,pid,yzcode) ; -
檢視索引
show index from region ; -
新增索引
alter table region add index name_pid_yzcode (name,pid,yzcode) ; -
刪除索引
drop index name_pid_yzcode on region ;
alter table region drop index name_pid_yzcode ; -
explain select * from region where name = '元氏縣' ; explain select * from region where pid = '130100' ; -- 沒有用到索引 explain select * from region where yzcode = '051130' ;-- 沒有用到索引 explain select * from region where name = '元氏縣' and pid = '130100' ; explain select * from region where name = '元氏縣' and pid = '130100' and yzcode = '051130' ; explain select * from region where pid = '130100' and yzcode = '051130';-- 沒有用到索引
-
-
-
全文索引
-
定義
- fulltext型別的索引
- 自然語言的全文索引
- 常見單詞不會被搜尋,如果某個詞的初夏頻率超過50%
- 布林全文索引
-
解決了什麼問題
- 相比於使用模糊查詢提高了效率。
-
如何使用
-
建立索引
- create FULLTEXT index full_index on region (name) ;
-
檢視索引
- show keys from region ;
-
新增索引
- alter table region add FULLTEXT index full_index (name) ;
-
刪除索引
- drop index full_index on region ;
- alter table region drop index full_index ;
-
查詢使用索引
-
查詢格式:MATCH (columnName) AGAINST (‘string’);
-
查詢多列複合全文索引:
SELECT * FROM
student
WHERE MATCH(name
,address
) AGAINST(‘聰 廣東’) -
使用命令:
-
SHOW VARIABLES LIKE ‘ft%’; #ft就是FullText的簡寫 檢視所有的限制引數
- ft_boolean_syntax + -><()~*:""&| #改變IN BOOLEAN MODE的查詢字元,不用重新啟動MySQL也不用重建索引
min_word_len 4 #最短的索引字串,預設值為4,(通常改為1)修改後必須重建索引檔案
- ft_boolean_syntax + -><()~*:""&| #改變IN BOOLEAN MODE的查詢字元,不用重新啟動MySQL也不用重建索引
-
重新建立索引命令:repair table tablename quick
-
ft_max_word_len 84 #最長的索引字串,預設值為84,修改後必須重建索引檔案
-
ft_query_expansion_limit 20 #查詢括展時取最相關的幾個值用作二次查詢
-
ft_stopword_file (built-in) #全文索引的過濾詞檔案,具體可以參考:
-
-
自然語言 全文索引
select * from region where match (name) against(‘東城’); -
布林全文索引
select * from region where MATCH(name) AGAINST('橋西’IN BOOLEAN MODE) ;
-
-
-
索引的缺點
-
佔用磁碟空間
首先,索引要佔用磁碟空間。通常情況下,這個問題不是很突出。但是,如果你建立每一種可能列組合的索引,索引檔案體積的增長速度將遠遠超過資料檔案。如果你有一個很大的表,索引檔案的大小可能達到作業系統允許的最大檔案限制。
-
增加增刪改時間
對於需要寫入資料的操作,比如DELETE、UPDATE以及INSERT操作,索引會降低它們的速度。這是因為MySQL不僅要把改動資料寫入資料檔案,而且它還要把這些改動寫入索引檔案。
-
-
索引失效情況
-
在索引列上使用: is null 如果列值可以為null索引有效,如果列值不能為null,索引失效; is not null 索引失效;
-
create index name_index on region (name) ; show keys from region ; update region set name = null where id = '900002' ; explain select * from region where name is null ; ## 索引生效 name 可以為 null explain select * from region where name is not null ; ## 索引失效 drop index name_index on region ; show keys from student ; create unique index name_index on student (name) ; ## 修改 name屬性不能為null explain select * from student where name is null ; ## 索引失效 name 不能為 null explain select * from student where name is not null ; ## 索引失效 explain select * from student where id is null ; ## 索引失效 primary key id
-
-
or關鍵字, 網上說的情況是:其中一個條件列上面沒有索引,沒有索引怎麼會生效,真是無語!
-
## name 有索引,pid沒有索引 explain select * from region where name = '沙田區' or pid = '110000' ;## 索引不生效 explain select * from region where pid = '110000' or name = '沙田區' ;## 索引不生效 explain select * from region where name = '大堂區' or name = '氹仔島' ; ## 索引生效
-
-
複合索引沒有遵循最左匹配原則時,查詢條件中如果沒有最左的那列,索引不生效
-
create index name_pid_yzcode on region (name,pid,yzcode) ; explain select * from region where pid = '110000' and yzcode = '100000' ; ## 索引不生效
-
-
使用like ‘%str%’ ‘%str’ ,索引不生效
-
explain select * from region where name like '沙田%' ; ## 索引生效 explain select * from region where name like '%沙田區%' ;## 索引不生效 explain select * from region where name like '%田區' ;## 索引不生效
-
-
普通索引上使用邏輯運算子: != 索引無效,
-
explain select * from region where id != 900001 ; ## primary key 索引有效 create index level_index on region (level) ; show index from region ; explain select * from region where level != 1 ; ## 索引失效 普通索引
-
-
使用比較運算子:±*/ ,還有函式運算 ,沒有在索引列上直接指定結果,索引失效
-
explain select * from region where level+1 = 2 ; ## 索引失效 explain select * from region where level-1 = 1 ; ## 索引失效 explain select * from region where level*1 = 2 ; ## 索引失效 explain select * from region where level/1 = 3 ; ## 索引失效 explain select * from region where level = ( select max(level) from region ) ; ## 索引失效 這個好像不太合適!!嘻嘻
-
-
show status like ‘Handler_read%’;
-
-
聚簇索引和非聚簇索引
更新中····(哈哈哈)
-