如何優化sql,效率最高,SQL索引優化

索引概念和作用
索引是一種使記錄有序化的技術,它可以指定按某 列/某幾列預先排序,從而大大提高查詢速度(類似 於漢語詞典中按照拼音或者筆畫查找)。
索引的主要作用是加快數據查找速度,提高數據庫 的性能。

MySQL索引類型
從物理存儲角度上,索引可以分爲聚集索引和非聚 集索引。
1.聚集索引(Clustered Index)
聚集索引決定數據在磁盤上的物理排序,-個表只 能有一個聚集索引。
2.非聚集索引(Non-clustered Index)
引上只包含被建立索引的數據,以及一個行定位符 row-locator, 這個行定位符,可以理解爲一個聚集 索引物理排序的指針,通過這個指針,可以找到行 數據

從邏輯角度,索引可以分爲以下幾種。
1.普通索引:最基本的索引,它沒有任何限制。2.唯一索引:與普通索引類似,不同的就是索引 列的值必須唯一-, 但允許有空值。如果是組合 索引,則列值的組合必須唯-
3.主鍵索引:它是一種特殊的唯一 索引,用於唯ll 一標識數據表中的某一條記錄, 不允許有空 值,- -般用primary key來約束。主鍵和聚 集索引的關係詳見"問題詳解”中的第4題。4.聯合索引(又叫複合索引) :多個字段上建立 的索引,能夠加速複合查詢條件的檢索。5.全文索引:老版本 MySQL自帶的全文索引 只能用於數據庫引擎爲MyISAM的數據表, 新版本MySQL 5.6的InnoDB支持全文索引 默認MySQL不支持中文全文檢索,可以通過 擴展MySQL,添加中文全文檢索或爲中文內 容表提供對應的英文索引表的方式來支持

MySQL索引優化規則
可以通過以下規則對MySQL索引進行優化。
1.前導模糊查詢不能使用索引。
例如下面SQL語句不能使用索引。
select * fromdoc where title like '%XX’ 而非前導模糊查詢則可以使用索引,如下面的SQL 語句。
select * fromdoc where title like ‘XX%’
頁面搜索嚴禁左模糊或者全模糊,如果需要可以用 搜索引擎來解決。
2.union、 in、 or 都能夠命中索引,建議使用in。
示例代碼如下:
select * fromdoc where status=1
unionall
select * fromdoc where status=2
直接告訴MySQL怎麼做,MySQL 耗費的CPU最 少,但是-般不這麼寫sQL。
●in:能夠命中索引。.
示例代碼如下:
select * fromdoc where status in (1, 2) 查詢優化耗費的CPU比union all多,但可以忽略 不計,一般情況下建議使用in
●or:新版的MySQL能夠命中索引。
示例代碼如下:
select * fromdoc where status= 1 or status =2 查詢優化耗費的CPU比in多,不建議頻繁用or。3.負向條件查詢不能使用索引, 可以優化爲in查 詢
負向條件有: !=、<>、not in、not exists、not like 等
例如下面代碼:
select * fromdoc where status != 1 and status != 2 可以優化爲in查詢:
select * fromdoc where status in (0,3,4)
4.聯合索引最左前綴原則(又叫最左側查詢)
●如果在(a,b,c)三個字段上建立聯合索引,那麼 它能夠加快a I(a,b) |(a,b,c)三組查詢速度。
例如登錄業務需求,代碼如下。
selectuid,
login_ time from user where login. name=? andpas 可以建立(login name, passwd)的聯合索引。
因爲業務上幾乎沒有passwd的單條件查詢需求, 而有很多login
name的單條件查詢需求,所以可
(passwd, login. name)。
●建聯合索引的時候,區分度最高的字段在最左
●如果建立了(a,b)聯合索引,就不必再單獨建立 a索引。同理,如果建立了(a,b,c)聯合索引,
就不必再單獨建立a、(a,b) 索引。
●存在非等號和等號混合判斷條件時,在建索引 時,請把等號條件的列前置。如where a>?
and b=?,那麼即使a的區分度更高,也必須
把b放在索引的最前列。
●最左側查詢需求,並不是指SQL語句的 where順序要和聯合索引- -致。
下面的SQL語句也可以命中(login. name, passwd) 這個聯合索引。
selectuid,
login
time from user where passwd=? andlogin. na me=2
但還是建議where後的順序和聯合索引一致,養成 好習慣。
5.範圍列可以用到索引(聯合索引必須是最左前
●範圍列可以用到索引(聯合索引必須是最左前’ 綴) ,但是範圍列後面的列無法用到索引,索 引最多用於- -個範圍列,如果查詢條件中有兩| 個範圍列則無法全用到索引。
假如有聯合索引(empno、title、 fromdate), 那麼 下面的SQL中emp. no可以用到索引,而title和 from
.date則使用不到索引。
select * fromemployees. titles where emp_no< 10010’ and title='Senior Engineer and from
date between ‘1986-01-01’ and ‘1986-12-31’
6.把計算放到業務層而不是數據庫層。
附:如果使用
select * fromdoc where create
time<=YEAR ( '2016-03-12 12:12:12);
依然會用到索引;
●在字段上進行計算不能命中索引。
例如下面的SQL語句。
select * fromdoc where YEAR(create_ time)<= ‘2016’
即使date.上建立了索引,也會全表掃描,可優化爲 值計算,如下:
select * fromdoc where create
_time <= ‘201 6-01-
●把計算放到業務層。
這樣做不僅可以節省數據庫的CPU,還可以起到查 詢緩存優化效果。
比如下面的SQL語句:
select * fromorder where date < = CURDATE( 可以優化爲:
select * fromorder where date < = 2018-01-2412:00:00’
優化後的SQL釋放了數據庫的CPU多次調用,傳 入的SQL相同,纔可以利用查詢緩存。
7.強制類型轉換會全表掃描
如果phone字段是varchar類型,則下面的SQL不 能命中索引。
select * fromuser where phone=13800001234
可以優化爲:
select * fromuser where phone='13800001234’8.更新十分頻繁、數據區分度不高的字段上不宜建 立索引。
●更新會變更B+樹,更新頻繁的字段建立索引 會大大降低數據庫性能
“性別”這種區分度不大的屬性,建立索引是沒
有什麼意義的,不能有效過濾數據,性能與全 表掃描類似。

  • -般區分度在80%以上的時候就可以建立索 引,區分度可以使用count(distinct(列 名))/count() 來計算。
    9.利用覆蓋索引來進行查詢操作,避免回表。
    數據能從索引中取得,而不用通過行
    定位符row-locator再到row.上獲取,即"被查詢列 要被所建的索引覆蓋",這能夠加速查詢速度。
    例如登錄業務需求,代碼如下。
    selectuid,
    login_ time from user where login name=? andpas swd=?
    可以建立(login
    name, passwd, login. time)的聯合 索引,由於login. time已經建立在索引中了,被查 詢的uid和login. time就不用去row上獲取數據 了,從而加速查詢。
    10.如果有order by、group by的場景,請注意利用 索引的有序性。
    ●order by 最後的字段是組合索引的-部分, 並且放在索引組合順序的最後,避免出現 file
    sort 的情況,影響查詢性能。, 例如對於語句where a=? and b=? order by c,可以建立聯合索引(a,b.c)。
    。如果索引中有範圍查找,那麼索引有序性無法"| 利用,如WHERE a 利用,如WHERE a210 ORDERBYb:索引(a,b)無法排序。
    11.使用短索引(又叫前綴索引) 來優化索引。
    前綴索引,就是用列的前綴代替整個列作爲索| key,當前綴長度合適時,可以做到既使得前綴索引 的區分度接近全列索引,同時因爲索引key變短而 減少了索引文件的大小和維護開銷,可以使用 count(distinct left(列名,索引長度))/count(
    )來計 算前綴索引的區分度。
    前綴索引兼顧索引大小和查詢速度,但是其缺點是 不能用於ORDER BY和GROUP BY操作,也不能用 於覆蓋索引(Covering Index,即當索引本身包含 查詢所需全部數據時,不再訪問數據文件本身) 很多時候沒必要對全字段建立索引,根據實際文本 區分度決定索引長度即可。
    11.使用短索引(又叫前綴索引)來優化索引。
    前綴索引,就是用列的前綴代替整個列作爲索引
    key,當前綴長度合適時,可以做到既使得前綴索引
    的區分度接近全列索引,同時因爲索引key變短而
    減少了索引文件的大小和維護開銷,可以使用
    count(distinct left(列名,索引長度))/count()來計
    算前綴索引的區分度。
    前綴索引兼顧索引大小和查詢速度,但是其缺點是 不能用於ORDER BY和GROUP BY操作,也不能用 於覆蓋索引(Coverinq Index,即當索引本身包含 查詢所需全部數據時,不再訪問數據文件本身) 很多時候沒必要對全字段建立索引,根據實際文本 很多時候沒必要對全字段建立案引,根據實際文本 區分度決定索引長度即可。
    例如對於下面的SQL語句:
    SEL EC FROM employees.employees WHERE first_ name='Eric’AND last_ name=‘Anido’;
    我們可以建立索引: (firstname, lastname())。.
    12.建立索引的列,不允許爲null。
    單列索引不存null值,複合索引不存全爲null的 值,如果列允許爲null,可能會得到"不符合預期”的! 結果集,所以,請使用not null約束以及默認值。
    13.利用延遲關聯或者子查詢優化超多分頁場景。
    MySQL並不是跳過offset 行,而是取offset+N 行,然後返回放棄前offset行,返回N行,那當 offset特別大的時候,效率就非常的低下,要麼控 制返回的總頁數,要麼對超過特定閾值的頁數進行 SOL改寫。
    selecta.
    fr
    件limit100000,20 ) b where a.id=b.id
    14.業務.上具有唯一特性的字段,即使是多個字段的! 組合,也必須建成唯-索引。
    不要以爲唯一索引影響了 insert 速度,這個速度損 耗可以忽略,但提高查找速度是明顯的。另外,即 使在應用層做了非常完善的校驗控制,只要沒有唯 一索引, 根據墨菲定律,必然有髒數據產生。
    15.超過三個表最好不要join。
    需要join的字段,數據類型必須-致,多表關聯查 詢時,保證被關聯的字段需要有索引o
    16.如果明確知道只有一條結果返回, limit 1能夠提} 高效率。
    比如如下SQL語句:
    select * fromuser where login_name=? 可以優化爲:
    select * fromuser where login_ name=? limit 1 自己明確知道只有一條結果, 但數據庫並不知道, 明確告訴它,讓它主動停止遊標移動。
    17 .sQL性能優化explain中的type:至少要達到 range 級別,要求是ref級別,如果可以是consts 最好
    ●consts:單表中最多隻有一一個匹配行(主鍵或 者唯- -索引) ,在優化階段即可讀取到數據。 ref:使用普通的索引(Normal Index),●range: 對索引進行範圍檢索。
    ●當type=index時,索引物理文件全掃,速度 非常慢。
    18.單表索引建議控制在5個以內。
    19.單索引字段數不允許超過5個。
    字段超過5個時,實際已經起不到有效過濾數據的作
    了。
    20.創建索引時避免以下錯誤觀念
    ●索引越多越好,認爲一個查詢就需要建一-個索
    ●寧缺勿濫,認爲索引會消耗空間、嚴重拖慢更
    新和新增速度。
    ●抵制惟一索引,認爲業務的惟一性一-律需要在 應用層通過“先查後插’方式解決。●過早優化,在不瞭解系統的情況下就開始優 化。
    問題詳解
    這部分,我將列出平時會遇到的一些問題,並給予 解答。
    1.請問如下三條SQL該如何建立索引?
    where a=1and b=1
    where b=1
    where b=1 order by time desc
    MySQL的查詢優化器會自動調整where子句的條 件順序以使用適合的索引嗎?
    回答:
    第一問:建議建立兩個索引,即idxab(a,b)和 idxbtime(,time)。
    第二問: MySQL的查詢優化器會自動調整where 子句的條件順序以使用適合的索引,對於上面的第-條SQL,如果建立索引爲idxba(b,a)也是可以用 到索引的,不過建議where後的字段順序和聯合索 引保持一致,養成好習慣。
    2.假如有聯合索引(empno、title、 fromdate), 下面| 的SQL是否可以用到索引,如果可以的話,會使用 幾個列?
    select * fromemployees titles where emp _no betw een 10001’ and’1 0010’ andtitle=‘Senior Enaineer’ and from date between 1986-01- Engieer andtrom-
    01 and ‘1986-12-31’
    回答:可以使用索引,可以用到索引全部三個列, 這個SQL看起來是用了兩個範圍查詢,但作用於
    empno實際是多值精確匹配,在MySQL中要謹慎 地區分多值匹配和範圍匹配,否則會對MySQL的 行爲產生困惑。
    3.既然索引可以加快查詢速度,那麼是不是隻要是 查詢語句需要,就建上索引?
    回答:不是,因爲索引雖然加快了查詢速度,但索 引也是有代價的。索引文件本身要消耗存儲空間, 同時索引會加重插入、刪除和修改記錄時的負擔。 另外,MySQL在運行時也要消耗資源維護索引,因 此索引並不是越多越好。一般兩種情況下不建議建 索引。第-種情況是表記錄比較少,例如- -兩千條 甚至只有幾百條記錄的表,沒必要建索引,另-種 是數據的區分度比較低,可以使用
    count(distinct(列名))/count(
    ) 來計算區分度。
    4.主鍵和聚集索引的關係?
    回答:在MySQL中,InnoDB引擎表是(聚集)索
    先按照主鍵進行聚集,如果沒有定義主鍵,InnoDB 會試着使用唯一-的非空索引來代替, 如果沒有這種 索引,InnoDB 就會定義隱藏的主鍵然後在上面進行 聚集。由此可見,在InnoDB表中,主鍵必然是聚 集索引,而聚集索引則未必是主鍵。MyISAM引擎 表是堆組織表(Heap Organize Table),它沒有聚集’ 索引的概念。
    5.- 個6億的表a, - -個3億的表b,通過外鍵tid關 聯,如何最快的查詢出滿足條件的第10000到第50200中的這200條數據記錄?
    回答:方法一:如果a表tid是自增長,並且是連 續的,b表的id爲索引。SQL語句如下。
    select * froma,b where a.tid =
    b.id and a.tid> 500000 limit200;
    方法二:如果a表的tid不是連續的,那麼就需要 使用覆蓋索引,tid 要麼是主鍵,要麼是輔助索引, b表id也需要有索引。SQL語句如下。
    select * fromb, (select tid from a limit 50000,200) awhere b.id= a.tid;
    6.假如建立聯合索引(a,b,c),下列語句是否可以使 用索引,如果可以,使用了那幾列? (考察聯合索 店
    引最左前綴原則)
    where a= 3
    答:是,使用了a列。
    where a= 3and b=5
    答:是,使用了a, b列。
    wherea= 3 andc=4 and b=5
    答:是,使用了a, b, c列。
    where b= 3
    答:否。
    wherea=3andc=4
    答:是,使用了a列。
    wherea= 3 and b> 10 andc= 7
    答:是,使用了a, b列。
    where a= 3 and b like ‘Xx%’ andc = 7 答:是,使用了a, b列。
    7.文章表的表結構如下:
    CREATE TABL EIF NOT EXISTS article* (id"int(10) unsigned NOTNULL AUTO INCREMENT,
    、author. jid’ int(10) unsignedNOT NULL,
    、category jid int(10) unsigned NOT NULL,
    ‘views’ int(10) unsignedNOT NULL,
    、comments int(10) unsignedNOT NULL,
    "tite’ varbinary(255) NOT NULL,
    、content text NOTNULL,
    PRIMARY KEY (id)
    下面語句應該如何建立索引?
    selectauthor. jid, title, content from article’ wherecategory_id = 1 and comments> 1 order byviews desc limit 1;
    回答:
    沒有聯合索引時,explain顯示, 如下圖所示:
    idxcategoryidcommentsviews(category
    id,comme nts, views)聯合索引時,explain顯示, 如下圖所

    創建idxcategoryidviews(categoryid,iews)聯合索 引,explain 顯示,如下圖所示:
    由此可見,可以創建
    idxcategoryidviews(categoryid,views)聯合索引。
    結語
    對於大數據量的業務,應該時刻考慮到性能,本文 只是從使用層面提供了- -些優化的思路,由於業務 和數據的複雜性,需要具體問題具體分析,對於數 據量比較大的業務,最好自己使用explain具體分 析一下、同時、知其然知其所以然,有時間大家可
    以看看索引的底層實現原理。 歡迎各路大神拍磚, 以看看系5
    共同學習

Explain
6 mysql
1)、id列數字越大越先執行,如果說數字-樣大,那麼就 從上往下依次執行,id列爲null的就表是這是一一個結果集, 不需要使用它來進行查詢。
2)、select type列常見的有:
A: simple:表示不需要nion操作或者不包含子查詢的簡 單select查詢。 有連接查詢時,外層的查詢爲simplnple, 且 有一個
Selet, 1最個需要union操作或者含有子查詢的 B: primary: 一個需要u select, 位於最外層的單位查詢的select. type即爲
C: union: union連接的兩個select查詢,第- -個查詢是 dervied派生表, 除了第- -個表外,第二個以後的表 select type都是union
D: dependent union;與union- 樣,出現在union 或union al語句中,但是這個查詢要受到外部查詢的影響 E: union result:包含union的結果集,
語句中,因爲它不需要參與的,果集,在nion和ounion al
i subquery:除了from字句中包含的子查詢外,其他地方
的子查詢都可能是subquery
G: dependent subquery:與dependent union類似,表示 這個subquery的查詢要受到外部表查詢的影響 H: derived: from字句中出現的子查詢,也叫做派生表, 其他數據庫中可能叫做內聯視圖或嵌套select
3)、table
是別名,如秦不,如果查詢使用了別名,那麼這裏顯示的. 顯示的查詢表名,如果查詢使用 死梨名,如果不涉及對數據表的操作,那麼這顯示爲nul,
示爲尖括號括起來的就表示這個是臨時 表,後邊的N就是執行計劃中的id,表示結果來自於這個查
詢產生。如果是尖括號括起來的

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章