一.表結構優化
二.列類型優化
三.索引優化策略
四.聚簇索引和非聚簇索引
五.理想的索引
怎么查看一個sql語句的執行效果
在sql語句前面加上 “explain”,如果加上"\\\\G",則能看到豎列效果 explain sql \\\\G
結果中的 key_len 就是在查詢上所用到的索引的個數; using filesort就是用到了排序的意思;using index是用到了索引覆蓋
排序非常耗資源,想分組,必須排序
測試運行需要的時間 time file.php
如果A\\\\B兩張表結構是一樣的,把A表里面的數據插入B表,
可以這樣執行:insert into B select * from A;
如果要插入某個字段的數據
insert into B select id,name,age from A;
在數據庫終端指令, 如果要查看前幾個 sql語句運行時間,show profiles;這個時候只能看到小數點后兩位,
如果要看到精確的運行時間。set profiling = on;
如果某個表查詢的時候出現了亂碼,在終端 set names utf8;
delimiter $ //在終端輸入$才會結束一條語句
優化總則
1.少查(能不查就不查)
2.查少(少查點數據)
3.快點查(走索引)
4.少排序
一.表結構優化
1.定長和變長分離
如id int,占4個字節,char(4)占4個字段長度,也是定長,time 即每一個單元值占的字節是固定的
而varchar,text,blob,這種變長字段,適合單放一張表,用主鍵與核心表關聯起來
2.常用字段和不常用字段分表,通過uuid將兩張表關聯。這個需要結合網站的具體業務來分析,分析字段的查詢場景,查詢頻率低的字段,單拆出來(用空間來換取時間)
比如兩張關聯表,一個是板塊表(cat),另一個是板塊下回復的帖子。查詢某個板塊下有多少個回復
方法一:先查出有幾個板塊,再在for循環里面找每個板塊下有多少回復
select * from cat; //比如10個板塊
for($i=1; $i<=10; $i++){
select count(*) from post where cat_id = $i;
}
方法二,使用左右連接查詢,比較消耗資源,不推薦
select cat.* from cat left join post on cat.cat_id = post.cat_id group by cat_id;
如果我們需要實時計算帖子的數量,可以在cat表里面再加一個num字段,每次有人發帖,讓這個字段用update更新加1,這是最好的方法。
二.列類型優化
字段類型選擇原則
整型>date,time,>enum,char>varchar>blob,text
列的特點分析:
整型:定長,沒有國家/地區之分,沒有字符集的差異
比如,tinyint 1,2,3,4,5 <--> char(1) a,b,c,d
從空間上,都是占1個字節,但是order by排序,前者快
原因:char需要考慮字符集與校對級(就是排序規則)
time 定長,運算快,節省空間,考慮時區時,寫sql時不方便 where > '2016-10-11';
enum:定長,能起約束的目的,內部用整型來存儲,但與char聯查時,內部要經歷串與值得轉化
Char 定長,考慮字符集的轉換與排序時的校對集
varchar,不定長,要考慮字符集的轉換與排序時的校對集,速度慢
text/blob,無法使用內存臨時表(排序等操作只能在磁盤上進行)
三.索引優化策略
1.索引類型
1.1Btree索引(二叉樹就是索引)--適用于范圍的查詢
名叫btree索引,大的方面看,都是用的平衡樹,但是具體的實現上,各引擎稍有不同
比如,嚴格說NDB引擎,使用的是T-tree
Mysiam,innodb中默認使用B-tree
但抽象一下,B-tree系統可以理解為"排好序的快速查找結構"
1.2hash索引(只在內存表里面使用hash索引)
在memory表里默認是hash索引,hash里的理論查詢時間復雜度為0(1)(一次就能找到)
hash的特點:
1.隨機性:hash函數計算后的結果,是隨機的,如果是在磁盤上放置數據,
比如主鍵為id,那么隨著id的增長,id對應的行,在磁盤上隨機放置
2.無法對范圍查詢進行優化
3.(離散性)無法利用前綴索引,比如在btree中,field列的值"helloworld",加索引, hash(helloworld)和hash(hello),兩者沒有關系。
4.排序也法優化(它是隨機分配數據的)
5.必須回行,也就是說,通過索引拿到數據位置,必須回到表中取數據
2.btree索引常見的誤區
要查詢的字段都建立了索引,并不是都可以使用得到。查詢的時候遵循左前綴規則
2.索引的左前綴規則--比如index(a,b,c)
語句 | 索引是否發揮作用 |
---|---|
where a=3 | 是,只使用了a列 |
where a=3 and b=5 | 是,只用了a,b列 |
where a=3 and b=5 and c=4 | 是,使用了abc列 |
where b=3 / where c=4 | 否 |
where a=3 and c=4 | a列能發揮索引,c不能 |
where a=3 and b>10 and c=7 | A能利用,b能利用,c不能利用 |
同上,where a=3 and b like"xxx%" and c=7 | A能利用,b能利用,c不能利用 |
四.聚簇索引和非聚簇索引
Myisam用的是非聚簇索引:主鍵和次索引都指向物理行磁盤的位置
數據是數據 獨立文件 xx.myd
索引是索引 獨立文件 xx.myi
兩者不摻和 這就是非聚簇
它的查找是先根據索引查找到主鍵的值,值旁邊有一個地址,在地址上去查找你要的信息,這個過程叫“回行”。
但是innodb聚簇,值得旁邊直接就是行信息。這就是他們的本質信息
innodb用的是聚簇索引:innodb的主索引文件上,直接存放該行數據,稱為聚簇索引,次索引指向對主鍵的作用
注意:對innodb來說
1.主鍵索引 既存儲索引,又在葉子中存儲行的數據
2.如果沒有主鍵(primary key),則會unique key做主鍵
3.如果沒有unique,則系統生成一個內部的 rowid 做主鍵
4.像innodb中,主鍵的索引結構中,既存儲了主鍵的值,又存儲了行數據,這種結構稱為"聚簇索引"
聚簇索引
優勢:根據主鍵查詢條目比較少時,不用回行(數據就在主節點下)
劣勢:如果碰到不規則數據插入時,造成頻繁的頁分裂
索引覆蓋
索引文件中,myi有你需要的字段,就不需要回行。這就是索引覆蓋
explain sql \\\\G 如果在extra里面出現了"using index",就是用了索引覆蓋,查詢效率會很高
比如:如果表A中c1建立了索引
explain select c1 from A where c1>5 \\\\G; 這個時候就用到了索引覆蓋
explain select c1,c2 from A where c1>5 \\\\G;如果c2沒有索引 這個時候沒用索引覆蓋。因為c2在索引里面找不到,需要回行
五.理想的索引
1. sql查詢中也可以直接使用函數,例如查詢詞典表中最長的兩個單詞:
select * from dict order by length(word) desc limit 2;
2.取10個,單詞的左邊只有一個值的:
select left(word,1) from dict limit 10;
3.取重復的
select distinct left(word,1) from dict limit 10;
select count( distinct left(word,1) ) from dict;
2.偽哈希索引技巧
用于存儲url,有兩種方法。1,列內容倒過來存儲并建立索引。這樣左前綴區分度大。
2.偽hash索引效果同時存url hash列
create table A( id int primary key,
url char(60) not null default '' );
insert into A values(1,"www.baidu.com"),
(2,"www.sina.com"),(3,"www.itxdl.com");
alert table A add urlcrc int unsigned not null;
在sql存儲時,crccurl == crc32(url)
因為crc的結果是32位,int 無符號數,因此當數據超過40億也會有重復,但這是是的的。(索引長度為int4個字節)
select crc32('str'); //可以把任何字符串轉換成數字
商品建立索引,一般兩種方式
以,欄目、價格 index(cat_id, price); 或者欄目、品牌、價格 index(cat_id,brand_id,shop_price);
索引與排序有兩種情況
1.對于覆蓋索引,直接在索引上查詢時,就是有序的,using,index
在innodb引擎中,沿著索引字段排序,也是自然有序的,對于myisam引擎,如果按某種索引字段排序,如id,但去除的字段中未有索引字段,如goods_name,myisam的做法,不是 索引->回行,而是先去除所有的行,再進行排序
2.先去除數據,形成臨時表做filesort(文件排序,但文件可能在磁盤上,也可能在內存中)