1. 程式人生 > 實用技巧 >一文帶你瞭解Sql優化

一文帶你瞭解Sql優化

我們後臺開發人員每天都難免與資料庫打交道,那麼你在寫sql語句的時候有注重到自己sql的效率嗎?當你sql查詢速度很慢的時候你有想過是你的sql語句造成的嗎?看完這篇文章,我相信你會對sql優化有了一定的瞭解!

explain

通過檢視sql執行計劃來確定各部位的問題。使用方法:在sql語句前面加上explain關鍵字。

explain SELECT * FROM (SELECT id FROM sys_address where remarks='中國' or remarks='中國重慶'  or remarks='中國重慶重慶市' or remarks like '%渝北區%') a

執行結果:

id select_type table partitions type possible_keys key key_len ref rows filtered Extr
1 SIMPLE sys_address ALL 667651 35.2 Using where

引數說明:

  • id

id值越大,優先順序越高,就越先執行。如果id值一樣,那可以看成一組。

  • select_type

常見的值以及含義:

SIMPLE 簡單的select查詢,查詢中不包含子查詢或者UNION。

PRIMARY 查詢中若包含任何複雜的子部分,最外層查詢則被標記為PRIMARY。

SUBQUERY 在SELECT或WHERE列表中包含了子查詢。

DERIVED 在FROM列表中包含的子查詢被標記為DERIVED(衍生),MySQL會遞迴執行這些子查詢,把結果放在臨時表中。

UNION 若第二個SELECT出現在UNION之後,則被標記為UNION:若UNION包含在FROM子句的子查詢中,外層SELECT將被標記為:DERIVED。

UNION RESULT 從UNION表獲取結果的SELECT。

  • table

值就是當前執行的表名。

  • partitions

  • type

**執行效率 **system > const > eq_ref > ref > range > index > all

system:表僅有一行(=系統表)。這是const聯接型別的一個特例。

const:表最多有一個匹配行,它將在查詢開始時被讀取。因為僅有一行,在這行的列值可被優化器剩餘部分認為是常數。

const用於用常數值比較PRIMARY KEY或UNIQUE索引的所有部分時。

eq_ref:對於每個來自於前面的表的行組合,從該表中讀取一行。這可能是最好的聯接型別,除了const型別。它用在一個索引

的所有部分被聯接使用並且索引是UNIQUE或PRIMARY KEY。eq_ref可以用於使用= 操作符比較的帶索引的列。比較值可以為常量或

一個使用在該表前面所讀取的表的列的表示式。

ref:對於每個來自於前面的表的行組合,所有有匹配索引值的行將從這張表中讀取。如果聯接只使用鍵的最左邊的字首,或如

果鍵不是UNIQUE或PRIMARY KEY(換句話說,如果聯接不能基於關鍵字選擇單個行的話),則使用ref。如果使用的鍵僅僅匹配少量

行,該聯接型別是不錯的。ref可以用於使用=或<=>操作符的帶索引的列。

ref_or_null:該聯接型別如同ref,但是添加了MySQL可以專門搜尋包含NULL值的行。在解決子查詢中經常使用該聯接型別的

優化。

index_merge:該聯接型別表示使用了索引合併優化方法。在這種情況下,key列包含了使用的索引的清單,key_len包含了使

用的索引的最長的關鍵元素。

unique_subquery:該型別替換了下面形式的IN子查詢的ref:value IN (SELECT primary_key FROMsingle_table WHERE

some_expr);unique_subquery是一個索引查詢函式,可以完全替換子查詢,效率更高。

index_subquery:該聯接型別類似於unique_subquery。可以替換IN子查詢,但只適合下列形式的子查詢中的非唯一索引:

value IN (SELECT key_column FROM single_table WHERE some_expr)

range:只檢索給定範圍的行,使用一個索引來選擇行。key列顯示使用了哪個索引。key_len包含所使用索引的最長關鍵元素。

在該型別中ref列為NULL。當使用=、<>、>、>=、<、<=、IS NULL、<=>、BETWEEN或者IN操作符,用常量比較關鍵字列時,

可以使用range。

  • possible_keys

possible_keys列指出MySQL能使用哪個索引在該表中找到行。注意,該列完全獨立於EXPLAIN輸出所示的表的次序。這意味著

在possible_keys中的某些鍵實際上不能按生成的表次序使用。

  • key

key列顯示MySQL實際決定使用的鍵(索引)。如果沒有選擇索引,鍵是NULL。要想強制MySQL使用或忽視possible_keys列中的

索引,在查詢中使用FORCE INDEX、USE INDEX或者IGNORE INDEX。

  • key_len

key_len列顯示MySQL決定使用的鍵長度。如果鍵是NULL,則長度為NULL。注意通過key_len值我們可以確定MySQL將實際使

用一個多部關鍵字的幾個部分。

  • ref

ref列顯示使用哪個列或常數與key一起從表中選擇行。

  • rows

rows列顯示MySQL認為它執行查詢時必須檢查的行數。

  • filtered

  • Extr

該列包含MySQL解決查詢的詳細資訊。

Distinct:MySQL發現第1個匹配行後,停止為當前的行組合搜尋更多的行。

Not exists:MySQL能夠對查詢進行LEFT JOIN優化,發現1個匹配LEFT JOIN標準的行後,不再為前面的的行組合在該表內檢

查更多的行。

range checked for each record (index map: #):MySQL沒有發現好的可以使用的索引,但發現如果來自前面的表的列值已

知,可能部分索引可以使用。對前面的表的每個行組合,MySQL檢查是否可以使用range或index_merge訪問方法來索取行。

Using filesort:MySQL需要額外的一次傳遞,以找出如何按排序順序檢索行。通過根據聯接型別瀏覽所有行併為所有匹配

WHERE子句的行儲存排序關鍵字和行的指標來完成排序。然後關鍵字被排序,並按排序順序檢索行。

Using index:從只使用索引樹中的資訊而不需要進一步搜尋讀取實際的行來檢索表中的列資訊。當查詢只使用作為單一索引一

部分的列時,可以使用該策略。

Using temporary:為了解決查詢,MySQL需要建立一個臨時表來容納結果。典型情況如查詢包含可以按不同情況列出列的

GROUP BY和ORDER BY子句時。

Using where:WHERE子句用於限制哪一個行匹配下一個表或傳送到客戶。除非你專門從表中索取或檢查所有行,如果Extra值

不為Using where並且表聯接型別為ALL或index,查詢可能會有一些錯誤。

Using sort_union(...), Using union(...), Using intersect(...):這些函式說明如何為index_merge聯接型別合併索引掃描。

Using index for group-by:類似於訪問表的Using index方式,Using index for group-by表示MySQL發現了一個索引,可

以用來查詢GROUP BY或DISTINCT查詢的所有列,而不要額外搜尋硬碟訪問實際的表。並且,按最有效的方式使用索引,以便對於

每個組,只讀取少量索引條目。

索引

索引的作用就是加快查詢速度,它就像書的目錄,當你想獲取到裡面內容位置時,就需要可以通過目錄快速的定位到具體位置。

首先我們需要明確一點,索引並不是越多越好。因為寫入資料時,會對索引欄位進行一些處理,就會影響插入速度。

在MySql中的常用索引:

  • 主鍵索引

一個表中只有一個主鍵索引,一般在建表的時候就自動存在了。由系統自動建立,不需要額外手動建立。

  • 普通索引

一般索引。

ALTER TABLE table_name ADD INDEX 索引名(column1,column2);
  • 唯一索引

表示列中不能有重複值。

ALTER TABLE `table_name` ADD UNIQUE (`column`);
  • 全文索引

通常用於文字值中,比如商品詳細資訊等。

合理新增索引

  1. 查詢頻繁的欄位,應該新增索引。

  2. 更新頻繁的欄位,不應該新增索引。

  3. 唯一性太差的欄位不應該新增索引,比如sex性別欄位。

索引失效

以下幾種情況,即使欄位建立了索引,也不會使用到。

  1. like語句以“%”開頭。

  2. or語句的欄位沒有全部使用索引,其中任意一個沒有索引的話,此條件就不會使用索引。

  3. 在組合查詢中,第一個查詢欄位的名稱不是複合索引中的第一列。

  4. 在索引列上使用IS NULL 或者IS NOT NULL,索引是不能索引空值的,這樣的操作會導致全表掃描。

  5. 在索引欄位上使用not 、<>、!=。

  6. 在索引欄位上執行函式,如DATE_FORMAT(data, format)。