Explain優化查詢檢測mysql
所謂索引就是爲特定的mysql字段進行一些特定的算法排序,好比二叉樹的算法和哈希算法,哈希算法是經過創建特徵值,而後根據特徵值來快速查找,而用的最多,而且是mysql默認的就是二叉樹算法 BTREE,經過BTREE算法創建索引的字段,好比掃描20行就能獲得未使用BTREE前掃描了2^20行的結果。正則表達式
EXPLAIN能夠幫助開發人員分析SQL問題,explain顯示了mysql如何使用索引來處理select語句以及鏈接表,能夠幫助選擇更好的索引和寫出更優化的查詢語句. 使用方法,在select語句前加上Explain就能夠了:算法
Explain select * from blog where false;
複製代碼
mysql在執行一條查詢以前,會對發出的每條SQL進行分析,決定是否使用索引或全表掃描若是發送一條sql
select * from blog where false
複製代碼
Mysql是不會執行查詢操做的,由於通過SQL分析器的分析後MySQL已經清楚不會有任何語句符合操做;bash
Example函數
mysql> EXPLAIN SELECT `birday` FROM `user` WHERE `birthday` < "1990/2/2";
-- 結果:
id: 1
select_type: SIMPLE -- 查詢類型(簡單查詢,聯合查詢,子查詢)
table: user -- 顯示這一行的數據是關於哪張表的
type: range -- 區間索引(在小於1990/2/2區間的數據),這是重要的列,顯示鏈接使用了何種類型。從最好到最差的鏈接類型爲system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL,const表明一次就命中,ALL表明掃描了全表才肯定結果。通常來講,得保證查詢至少達到range級別,最好能達到ref。
possible_keys: birthday -- 指出MySQL能使用哪一個索引在該表中找到行。若是是空的,沒有相關的索引。這時要提升性能,可經過檢驗WHERE子句,看是否引用某些字段,或者檢查字段不是適合索引。
key: birthday -- 實際使用到的索引。若是爲NULL,則沒有使用索引。若是爲primary的話,表示使用了主鍵。
key_len: 4 -- 最長的索引寬度。若是鍵是NULL,長度就是NULL。在不損失精確性的狀況下,長度越短越好
ref: const -- 顯示哪一個字段或常數與key一塊兒被使用。
rows: 1 -- 這個數表示mysql要遍歷多少數據才能找到,在innodb上是不許確的。
Extra: Using where; Using index -- 執行狀態說明,這裏能夠看到的壞的例子是Using temporary和Using
複製代碼
select_type性能
Extra與type詳細說明大數據
其中type:優化
索引的類型ui
UNIQUE惟一索引
不能夠出現相同的值,能夠有NULL值
INDEX普通索引
容許出現相同的索引內容
PRIMARY KEY主鍵索引
不容許出現相同的值,且不能爲NULL值,一個表只能有一個primary_key索引
fulltext index 全文索引
上述三種索引都是針對列的值發揮做用,但全文索引,能夠針對值中的某個單詞,好比一篇文章中的某個詞,然而並無什麼卵用,由於只有myisam以及英文支持,而且效率讓人不敢恭維,可是能夠用coreseek和xunsearch等第三方應用來完成這個需求
索引的CURD
索引的建立
ALTER TABLE
適用於表建立完畢以後再添加
ALTER TABLE 表名 ADD 索引類型 (unique,primary key,fulltext,index)[索引名](字段名)
ALTER TABLE `table_name` ADD INDEX `index_name` (`column_list`) -- 索引名,可要可不要;若是不要,當前的索引名就是該字段名;
ALTER TABLE `table_name` ADD UNIQUE (`column_list`)
ALTER TABLE `table_name` ADD PRIMARY KEY (`column_list`)
ALTER TABLE `table_name` ADD FULLTEXT KEY (`column_list`)
複製代碼
CREATE INDEX
CREATE INDEX可對錶增長普通索引或UNIQUE索引
--例,只能添加這兩種索引;
CREATE INDEX index_name ON table_name (column_list)
CREATE UNIQUE INDEX index_name ON table_name (column_list)
複製代碼
另外,還能夠在建表時添加
CREATE TABLE `test1` (
`id` smallint(5) UNSIGNED AUTO_INCREMENT NOT NULL, -- 注意,下面建立了主鍵索引,這裏就不用建立了
`username` varchar(64) NOT NULL COMMENT '用戶名',
`nickname` varchar(50) NOT NULL COMMENT '暱稱/姓名',
`intro` text,
PRIMARY KEY (`id`),
UNIQUE KEY `unique1` (`username`), -- 索引名稱,可要可不要,不要就是和列名同樣
KEY `index1` (`nickname`),
FULLTEXT KEY `intro` (`intro`)
) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='後臺用戶表';
複製代碼
索引的刪除
DROP INDEX `index_name` ON `talbe_name`
ALTER TABLE `table_name` DROP INDEX `index_name`
-- 這兩句都是等價的,都是刪除掉table_name中的索引index_name;
ALTER TABLE `table_name` DROP PRIMARY KEY -- 刪除主鍵索引,注意主鍵索引只能用這種方式刪除
複製代碼
索引的查看
show index from tablename \G;
複製代碼
建立索引的技巧
1.維度高的列建立索引
數據列中不重複值出現的個數,這個數量越高,維度就越高 如數據表中存在8行數據a ,b ,c,d,a,b,c,d這個表的維度爲4 要爲維度高的列建立索引,如性別和年齡,那年齡的維度就高於性別 性別這樣的列不適合建立索引,由於維度太低
2.對 where,on,group by,order by 中出現的列使用索引
3.對較小的數據列使用索引,這樣會使索引文件更小,同時內存中也能夠裝載更多的索引鍵
4.爲較長的字符串使用前綴索引
5.不要過多建立索引,除了增長額外的磁盤空間外,對於DML操做的速度影響很大,由於其每增刪改一次就得重新創建索引
6.使用組合索引,能夠減小文件索引大小,在使用時速度要優於多個單列索引 組合索引與前綴索引
注意,這兩種稱呼是對創建索引技巧的一種稱呼,並不是索引的類型;
組合索引
MySQL單列索引和組合索引究竟有何區別呢?
爲了形象地對比二者,先建一個表:
CREATE TABLE `myIndex` (
`i_testID` INT NOT NULL AUTO_INCREMENT,
`vc_Name` VARCHAR(50) NOT NULL,
`vc_City` VARCHAR(50) NOT NULL,
`i_Age` INT NOT NULL,
`i_SchoolID` INT NOT NULL,
PRIMARY KEY (`i_testID`)
);
複製代碼
假設表內已有1000條數據,在這 10000 條記錄裏面 7 上 8 下地分佈了 5 條 vc_Name="erquan" 的記錄,只不過 city,age,school 的組合各不相同。 來看這條 T-SQL:
SELECT `i_testID` FROM `myIndex` WHERE `vc_Name`='erquan' AND `vc_City`='鄭州' AND `i_Age`=25; -- 關聯搜索;
複製代碼
首先考慮建MySQL單列索引: 在 vc_Name 列上創建了索引。執行 T-SQL 時,MYSQL 很快將目標鎖定在了 vc_Name=erquan 的 5 條記錄上,取出來放到一中間結果集。在這個結果集裏,先排除掉 vc_City 不等於"鄭州"的記錄,再排除 i_Age 不等於 25 的記錄,最後篩選出惟一的符合條件的記錄。 雖然在 vc_Name 上創建了索引,查詢時MYSQL不用掃描整張表,效率有所提升,但離咱們的要求還有必定的距離。一樣的,在 vc_City 和 i_Age 分別創建的MySQL單列索引的效率類似。 爲了進一步榨取 MySQL 的效率,就要考慮創建組合索引。就是將 vc_Name,vc_City,i_Age 建到一個索引裏:
ALTER TABLE `myIndex` ADD INDEX `name_city_age` (vc_Name(10),vc_City,i_Age);
複製代碼
建表時,vc_Name 長度爲 50,這裏爲何用 10 呢?這就是下文要說到的前綴索引,由於通常狀況下名字的長度不會超過 10,這樣會加速索引查詢速度,還會減小索引文件的大小,提升 INSERT 的更新速度。
執行 T-SQL 時,MySQL 無須掃描任何記錄就到找到惟一的記錄!!
若是分別在 vc_Name,vc_City,i_Age 上創建單列索引,讓該表有 3 個單列索引,查詢時和上述的組合索引效率同樣嗎?答案是大不同,遠遠低於咱們的組合索引。雖然此時有了三個索引,但 MySQL 只能用到其中的那個它認爲彷佛是最有效率的單列索引,另外兩個是用不到的,也就是說仍是一個全表掃描的過程。
創建這樣的組合索引,實際上是至關於分別創建了
vc_Name,vc_City,i_Age
vc_Name,vc_City
vc_Name
複製代碼
這樣的三個組合索引!爲何沒有 vc_City,i_Age 等這樣的組合索引呢?這是由於 mysql 組合索引**"最左前綴"**的結果。簡單的理解就是隻從最左面的開始組合。並非只要包含這三列的查詢都會用到該組合索引,下面的幾個 T-SQL 會用到:
SELECT * FROM myIndex WHREE vc_Name="erquan" AND vc_City="鄭州"
SELECT * FROM myIndex WHREE vc_Name="erquan"
複製代碼
而下面幾個則不會用到:
SELECT * FROM myIndex WHREE i_Age=20 AND vc_City="鄭州"
SELECT * FROM myIndex WHREE vc_City="鄭州"
複製代碼
也就是,name_city_age (vc_Name(10),vc_City,i_Age) 從左到右進行索引,若是沒有左前索引Mysql不執行索引查詢
前綴索引
若是索引列長度過長,這種列索引時將會產生很大的索引文件,不便於操做,可使用前綴索引方式進行索引 前綴索引應該控制在一個合適的點,控制在0.31黃金值便可(大於這個值就能夠建立)
SELECT COUNT(DISTINCT(LEFT(`title`,10)))/COUNT(*) FROM Arctic; -- 這個值大於0.31就能夠建立前綴索引,Distinct去重複
ALTER TABLE `user` ADD INDEX `uname`(title(10)); -- 增長前綴索引SQL,將人名的索引創建在10,這樣能夠減小索引文件大小,加快索引查詢速度
複製代碼
什麼樣的sql不走索引
要儘可能避免這些不走索引的sql
SELECT `sname` FROM `stu` WHERE `age`+10=30;-- 不會使用索引,由於全部索引列參與了計算
SELECT `sname` FROM `stu` WHERE LEFT(`date`,4) <1990; -- 不會使用索引,由於使用了函數運算,原理與上面相同
SELECT * FROM `houdunwang` WHERE `uname` LIKE'後盾%' -- 走索引
SELECT * FROM `houdunwang` WHERE `uname` LIKE "%後盾%" -- 不走索引
-- 正則表達式不使用索引,這應該很好理解,因此爲何在SQL中很難看到regexp關鍵字的緣由
-- 字符串與數字比較不使用索引;
CREATE TABLE `a` (`a` char(10));
EXPLAIN SELECT * FROM `a` WHERE `a`="1" -- 走索引
EXPLAIN SELECT * FROM `a` WHERE `a`=1 -- 不走索引
select * from dept where dname='xxx' or loc='xx' or deptno=45 --若是條件中有or,即便其中有條件帶索引也不會使用。換言之,就是要求使用的全部字段,都必須創建索引, 咱們建議你們儘可能避免使用or 關鍵字
-- 若是mysql估計使用全表掃描要比使用索引快,則不使用索引
複製代碼
多表關聯時的索引效率
從上圖能夠看出,全部表的type爲all,表示全表索引;也就是6_6_6,共遍歷查詢了216次;
除第一張表示全表索引(必須的,要以此關聯其餘表),其他的爲range(索引區間得到),也就是6+1+1+1,共遍歷查詢9次便可;
因此咱們建議在多表join的時候儘可能少join幾張表,由於一不當心就是一個笛卡爾乘積的恐怖掃描,另外,咱們還建議儘可能使用left join,以少關聯多.由於使用join 的話,第一張表是必須的全掃描的,以少關聯多就能夠減小這個掃描次數.
索引的弊端
不要盲目的建立索引,只爲查詢操做頻繁的列建立索引,建立索引會使查詢操做變得更加快速,可是會下降增長、刪除、更新操做的速度,由於執行這些操做的同時會對索引文件進行從新排序或更新;
可是,在互聯網應用中,查詢的語句遠遠大於DML的語句,甚至能夠佔到80%~90%,因此也不要太在乎,只是在大數據導入時,能夠先刪除索引,再批量插入數據,最後再添加索引;
note:咱們不要哀嘆生活的不幸,詛咒命運的不公。在命運面前,咱們要作強者,掐住命運的咽喉,叩問命運,改變命運。