mysql語句優化

1.通過show ststus命令瞭解sql的執行效率


value表示每個語句執行次數

2.定位效率低效的sql語句

一般通過以下兩種方式定位執行效率較低的 SQL 語句。 

通過慢查詢日誌定位那些執行效率較低的 SQL 語句,用 --log-slow-queries[=file_name] 選項啓動時, mysqld 會 寫一個包含所有執行時間超過 long_query_time 秒的 SQL 語句的日誌文件,通過查看這個日誌文件定位效率較低的 SQL 。 

慢查詢日誌在查詢結束以後才紀錄,所以在應用反映執行效率出現問題的時候查詢慢查詢日誌並不能定位問題,可以使用 show processlist 命令查看當前 MySQL 在進行的線程,包括線程的狀態、是否鎖表等,可以實時地查看 SQL 的 執行情況,同時對一些鎖表操作進行優化。

3.通過EXPLAIN分析低效的sql執行計劃

通過explain和desc命令可以查看mysql執行語句的信息。


簡單實用的優化方法

1.定期檢查表和分析表

分析表

analyze table sales;

檢查表

check table sales;

2.定期優化表(清理空間碎片)

optimize table sales;


sql優化

1.索引優化

MySQL只有對以下操作符才使用索引:<,<=,=,>,>=,BETWEEN,IN,以及某些時候的LIKE。

儘量不要寫!=或者<>的sql,用between或> and <代替,否則可能用不到索引

Order by 、Group by 、Distinct 最好在需要這個列上建立索引,利於索引排序

儘量利用mysql索引排序

沒辦法的情況下,使用強制索引Force index(index_name)

儘量避勉innodb用非常大尺寸的字段作爲主鍵

較頻繁的作爲查詢條件的字段應該創建索引;

選擇性高的字段比較適合創建索引;

作爲表關聯字段一般都需要創索引.

更新非常頻繁的字段不適合創建索引;

不會出現在 WHERE 子句中的字段不該創建索引.

選擇性太低的字段不適合單獨創建索引

2.優化insert

1. 對於Myisam 類型的表,可以通過以下方式快速的導入大量的數據。
ALTER TABLE tblname DISABLE KEYS;
loading the data
ALTER TABLE tblname ENABLE KEYS;
這兩個命令用來打開或者關閉Myisam 表非唯一索引的更新。在導入大量的數據到一
個非空的Myisam 表時,通過設置這兩個命令,可以提高導入的效率。對於導入大量
數據到一個空的Myisam 表,默認就是先導入數據然後才創建索引的,所以不用進行
設置。


2. 而對於Innodb 類型的表,這種方式並不能提高導入數據的效率。對於Innodb 類型
的表,我們有以下幾種方式可以提高導入的效率:
a. 因爲Innodb 類型的表是按照主鍵的順序保存的,所以將導入的數據按照主鍵的順
序排列,可以有效的提高導入數據的效率。如果Innodb 表沒有主鍵,那麼系統會默認
創建一個內部列作爲主鍵,所以如果可以給表創建一個主鍵,將可以利用這個優勢提高
導入數據的效率。
b. 在導入數據前執行SET UNIQUE_CHECKS=0,關閉唯一性校驗,在導入結束後執行SET
UNIQUE_CHECKS=1,恢復唯一性校驗,可以提高導入的效率。
c. 如果應用使用自動提交的方式,建議在導入前執行SET AUTOCOMMIT=0,關閉自動
提交,導入結束後再執行SET AUTOCOMMIT=1,打開自動提交,也可以提高導入的效率。


3. 如果你同時從同一客戶插入很多行,使用多個值表的INSERT 語句。這比使用分開INSERT 語句快(在一些情況中幾倍)。
Insert into test values(1,2),(1,3),(1,4)…


4. 如果你從不同客戶插入很多行,能通過使用INSERT DELAYED 語句得到更高的速度。
Delayed 的含義是讓insert 語句馬上執行,其實數據都被放在內存的隊列中,並
沒有真正寫入磁盤;這比每條語句分別插入要快的多;LOW_PRIORITY 剛好相反,
在所有其他用戶對錶的讀寫完後才進行插入;


5. 將索引文件和數據文件分在不同的磁盤上存放(利用建表中的選項);


6. 如果進行批量插入,可以增加bulk_insert_buffer_size 變量值的方法來提高速
度,但是,這隻能對myisam 表使用;


7. 當從一個文本文件裝載一個表時,使用LOAD DATA INFILE。這通常比使用很多
INSERT 語句快20 倍;
8. 根據應用情況使用replace 語句代替insert;
9. 根據應用情況使用ignore 關鍵字忽略重複記錄。


3.優化group by 

默認情況下,MySQL 排序所有GROUP BY col1,col2,....。查詢的方法如同在查詢中指定ORDER BY col1,col2,...。如果顯式包括一個包含相同的列的ORDER BY子句,MySQL 可以毫不減速地對它進行優化,儘管仍然進行排序。如果查詢包括GROUP BY 但你想要避免排序結果的消耗,你可以指定ORDER BY NULL禁止排序。

4.優化order by

在某些情況中,MySQL 可以使用一個索引來滿足ORDER BY 子句,而不需要額外的排序。where 條件和order by 使用相同的索引,並且order by 的順序和索引順序相同,並且order by 的字段都是升序或者都是降序。

5.優化or條件

對於有or的查詢子句,如果要使用索引,則or之間 每個條件都必須用索引,如果沒有,則考慮增加索引。

6.where語句的優化

儘量避免在 where 子句中對字段進行表達式操作
select id from uinfo_jifen where jifen/60 > 10000;
優化後:
Select id from uinfo_jifen where jifen>600000;


應儘量避免在where子句中對字段進行函數操作,這將導致mysql放棄使用索引

select uid from imid where datediff(create_time,'2011-11-22')=0
優化後
select uid from imid where create_time> ='2011-11-21‘ and create_time<‘2011-11-23’;


7.表的優化

儘可能的使用 NOT NULL
除非你有一個很特別的原因去使用 NULL 值,你應該總是讓你的字段保持 NOT NULL。
不要以爲 NULL 不需要空間,其需要額外的空間,並且,在你進行比較的時候,你的程序會更復雜。 
當然,這裏並不是說你就不能使用NULL了,現實情況是很複雜的,依然會有些情況下,你需要使用NULL值。
下面摘自MySQL自己的文檔:
“NULL columns require additional space in the row to record whether their values are NULL. For MyISAM tables, each NULL column takes one bit extra, rounded up to the nearest byt
e.”

固定長度的表會更快

如果表中的所有字段都是“固定長度”的,整個表會被認爲是 “static” 或 “fixed-length”。 例如,表中沒有如下類型的字段: VARCHAR,TEXT,BLOB。只要你包括了其中一個這些字段,那麼這個表就不是“固定長度靜態表”了,這樣,MySQL 引擎會用另一種方法來處理。
固定長度的表會提高性能,因爲MySQL搜尋得會更快一些,因爲這些固定的長度是很容易計算下一個數據的偏移量的,所以讀取的自然也會很快。而如果字段不是定長的,那麼,每一次要找下一條的話,需要程序找到主鍵。
並且,固定長度的表也更容易被緩存和重建。不過,唯一的副作用是,固定長度的字段會浪費一些空間,因爲定長的字段無論你用不用,他都是要分配那麼多的空間。


垂直分割

"垂直分割"是一種把數據庫中的表按列變成幾張表的方法,這樣可以降低表的複雜度和字段的數目,從而達到優化的目的。(以前,在銀行做過項目,見過一張表有100多個字段,很恐怖)

示例一:在Users表中有一個字段是家庭地址,這個字段是可選字段,相比起,而且你在數據庫操作的時候除了個人信息外,你並不需要經常讀取或是改寫這個字段。那麼,爲什麼不把他放到另外一張表中呢? 這樣會讓你的表有更好的性能,大家想想是不是,大量的時候,我對於用戶表來說,只有用戶ID,用戶名,口令,用戶角色等會被經常使用。小一點的表總是會有好的性能。

示例二: 你有一個叫 “last_login” 的字段,它會在每次用戶登錄時被更新。但是,每次更新時會導致該表的查詢緩存被清空。所以,你可以把這個字段放到另一個表中,這樣就不會影響你對用戶ID,用戶名,用戶角色的不停地讀取了,因爲查詢緩存會幫你增加很多性能。

另外,你需要注意的是,這些被分出去的字段所形成的表,你不會經常性地去Join他們,不然的話,這樣的性能會比不分割時還要差,而且,會是極數級的下降。


越小的列會越快

對於大多數的數據庫引擎來說,硬盤操作可能是最重大的瓶頸。所以,把你的數據變得緊湊會對這種情況非常有幫助,因爲這減少了對硬盤的訪問。

參看 MySQL 的文檔 Storage Requirements 查看所有的數據類型。

如果一個表只會有幾列罷了(比如說字典表,配置表),那麼,我們就沒有理由使用 INT 來做主鍵,使用 MEDIUMINT, SMALLINT 或是更小的 TINYINT 會更經濟一些。如果你不需要記錄時間,使用 DATE 要比 DATETIME 好得多。

當然,你也需要留夠足夠的擴展空間,不然,你日後來幹這個事,你會死的很難看,參看Slashdot的例子(2009年11月06日),一個簡單的ALTER TABLE語句花了3個多小時,因爲裏面有一千六百萬條數據。


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