不良的SQL往往來自于不恰當(dāng)?shù)乃饕O(shè)計肖方、不充份的連接條件和不可優(yōu)化的where子句。
一糜俗、 索引的建立和使用
- 定義主鍵的數(shù)據(jù)列一定要建立索引
- 定義有外鍵的數(shù)據(jù)列一定要建立索引
- 對于經(jīng)常查詢的數(shù)據(jù)列最好建立索引
- 對于需要在指定范圍內(nèi)的快速或頻繁查詢的數(shù)據(jù)列
- 經(jīng)常用在WHERE子句中的數(shù)據(jù)列
- 經(jīng)常出現(xiàn)在關(guān)鍵字order by、group by、distinct后面的字段蔗草,建立索引。如果建立的是復(fù)合索引疆柔,索引的字段順序要和這些關(guān)鍵字后面的字段順序一致咒精,否則索引不會被使用
- 對于那些查詢中很少涉及的列,重復(fù)值比較多的列不要建立索引
- 對于定義為text旷档、image和bit的數(shù)據(jù)類型的列不要建立索引
- 對于經(jīng)常存取的列避免建立索引
- 限制表上的索引數(shù)目模叙。對一個存在大量更新操作的表,所建索引的數(shù)目一般不要超過3個鞋屈,最多不要超過5個范咨。索引雖說提高了訪問速度故觅,但太多索引會影響數(shù)據(jù)的更新操作
- 對復(fù)合索引,按照字段在查詢條件中出現(xiàn)的頻度建立索引渠啊。在復(fù)合索引中输吏,記錄首先按照第一個字段排序。對于在第一個字段上取值相同的記錄替蛉,系統(tǒng)再按照第二個字段的取值排序贯溅,以此類推。因此只有復(fù)合索引的第一個字段出現(xiàn)在查詢條件中躲查,該索引才可能被使用,因此將應(yīng)用頻度高的字段它浅,放置在復(fù)合索引的前面,會使系統(tǒng)最大可能地使用此索引镣煮,發(fā)揮索引的作用
二姐霍、SQL語句的執(zhí)行原理
- 服務(wù)器在接收到查詢請求后,并不會馬上去數(shù)據(jù)庫查詢,而是在數(shù)據(jù)庫中的計劃緩存中找是否有相對應(yīng)的執(zhí)行計劃,如果存在,就直接調(diào)用已經(jīng)編譯好的執(zhí)行計劃,節(jié)省了執(zhí)行計劃的編譯時間
- 語法效驗、語義效驗典唇、權(quán)限驗證
- 針對SQL進行優(yōu)化,選擇不同的查詢算法以最高效的形式返回
- 語句執(zhí)行镊折,執(zhí)行順序:
1) FROM 子句返回初始結(jié)果集
2) WHERE 子句排除不滿足搜索條件的行
3) GROUP BY 子句將選定的行收集到 GROUP BY 子句中各個唯一值的組中
4) 選擇列表中指定的聚合函數(shù)可以計算各組的匯總值
5) 此外,HAVING 子句排除不滿足搜索條件的行
6) 計算所有的表達式
7) 使用order by對結(jié)果集進行排序 - where條件執(zhí)行原理及效率
首先要了解Where 條件執(zhí)行方向是從右向左的(如多條件判斷下蚓聘,會從最后一個條件來判斷過濾數(shù)據(jù)的腌乡,依次向前推進判斷)
1) 注意SQL運算符(非、與夜牡、或)優(yōu)先級別与纽,級別越高放最后
2) 在同運算符內(nèi)字段值數(shù)據(jù)范圍越大的查詢字段放最后
三、優(yōu)化SQL語句的若干方法
- WHERE 語句中塘装,小表字段寫左邊
- 在WHERE中盡量不要使用OR
- 操作符號: IN & NOT IN操作符
NOT IN操作是強列推薦不使用的急迂,NOT IN會多次掃描表
推薦方案:用NOT EXISTS 或(外連接+判斷為空)方案代替
而Exists比IN更快,最慢的是NOT操作
使用in時蹦肴,在IN后面值的列表中僚碎,將出現(xiàn)最頻繁的值放在最前面,出現(xiàn)得最少的放在最后面阴幌,這樣可以減少判斷的次數(shù)
另外勺阐,多表連接查詢時,用IN矛双,sql會先嘗試轉(zhuǎn)換成多表連接渊抽,轉(zhuǎn)換不成功則先執(zhí)行IN里面的查詢,再查詢外層表記錄议忽。 - 注意union和union all的區(qū)別懒闷。union比union all多做了一步distinct操作。能用union all的情況下盡量不用union
- 查詢時盡量不要返回不需要的行、列愤估。另外在多表連接查詢時帮辟,盡量改成連接查詢,少用子查詢
- Between在某些時候比IN速度更快,Between能夠更快地找到范圍
- 從右到左的順序處理FROM子句中的表名玩焰,選擇數(shù)據(jù)量少的表作為基礎(chǔ)表
- 沒有必要時不要用DISTINCT和ORDER BY由驹,它們增加了額外的開銷
- 計算記錄條數(shù)
和一般的觀點相反, count(*) 比count(1)稍快 , 當(dāng)然如果可以通過索引檢索,對索引列的計數(shù)仍舊是最快的. 例如 COUNT(CONTRACT_NO) - 減少對表的查詢
- 使用表的別名