經常使用sql優化

優化Group By語句

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

 

優化Order by語句

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

 

優化insert語句

若是你同時從同一客戶插入不少行,使用多個值表的INSERT 語句。這比使用分開 INSERT 語句快(在一些狀況中幾倍)。Insert into test values(1,2),(1,3),(1,4)…程序員

 

若是你從不一樣客戶插入不少行,能經過使用INSERT DELAYED 語句獲得更高的速度。Delayed 的含義是讓insert 語句立刻執行,其實數據都被放在內存的隊列中,並無真正的寫入磁盤;這比每條語句都分別插入要快的多;LOW_PRIORITY恰好相反,在全部其餘用 戶對錶的讀寫完成後才進行插入。sql

 

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

若是進行批量插入,能夠增長bulk_insert_buffer_size 變量值的方法來提升速度,可是,這隻能對myisam表使用緩存

 

當從一個文本文件裝載一個表時,使用LOAD DATA INFILE。這一般比使用不少INSERT語句快20倍;服務器

根據應用狀況使用replace 語句代替insert;函數

根據應用狀況使用ignore 關鍵字忽略重複記錄。性能

 

大批量插入數據

1. 對於Myisam 類型的表,能夠經過如下方式快速的導入大量的數據。mysql索引

ALTER TABLE tblname DISABLE KEYS;
loading the dataALTER TABLE tblname ENABLE KEYS;

這兩個命令用來打開或者關閉Myisam 表非惟一索引的更新。在導入大量的數據到一個非空的Myisam 表時,經過設置這兩個命令,能夠提升導入的效率。對於導入大量數據到一個空的Myisam 表,默認就是先導入數據而後才建立索引的,因此不用進行設置。

 

2. 而對於Innodb 類型的表,這種方式並不能提升導入數據的效率。對於Innodb 類型的表,咱們有如下幾種方式能夠提升導入的效率:

a. 由於Innodb 類型的表是按照主鍵的順序保存的,因此將導入的數據按照主鍵的順序排列,能夠有效的提升導入數據的效率。若是Innodb 表沒有主鍵,那麼系統會默認建立一個內部列做爲主鍵,因此若是能夠給表建立一個主鍵,將能夠利用這個優點提升導入數據的效率。
 

b. 在導入數據前執行SET UNIQUE_CHECKS=0,關閉惟一性校驗,在導入結束後執行SETUNIQUE_CHECKS=1,恢復惟一性校驗,能夠提升導入的效率。

c. 若是應用使用自動提交的方式,建議在導入前執行SET AUTOCOMMIT=0,關閉自動提交,導入結束後再執行SET AUTOCOMMIT=1,打開自動提交,也能夠提升導入的效率。

 

查詢的優化

讀爲主能夠設置low_priority_updates=1,寫的優先級調低,告訴MYSQL儘可能先處理讀求

 

 

爲查詢緩存優化你的查詢

大多數的MySQL服務器都開啓了查詢緩存。這是提升性最有效的方法之一,並且這是被MySQL的數據庫引擎處理的。當有不少相同的查詢被執行了屢次的時候,這些查詢結果會被放到一個緩存中,這樣,後續的相同的查詢就不用操做表而直接訪問緩存結果了。

這裏最主要的問題是,對於程序員來講,這個事情是很容易被忽略的。由於,咱們某些查詢語句會讓MySQL不使用緩存。請看下面的示例:

// 查詢緩存不開啓 
$r = mysql_query("SELECT username FROM user WHERE signup_date >= CURDATE()"); 
 
// 開啓查詢緩存 
$today = date("Y-m-d"); 
$r = mysql_query("SELECT username FROM user WHERE signup_date >= '$today'");

 

拆分大的 DELETE 或 INSERT 語句

若是你須要在一個在線的網站上去執行一個大的 DELETE 或 INSERT 查詢,你須要很是當心,要避免你的操做讓你的整個網站中止相應。由於這兩個操做是會鎖表的,表一鎖住了,別的操做都進不來了。

Apache 會有不少的子進程或線程。因此,其工做起來至關有效率,而咱們的服務器也不但願有太多的子進程,線程和數據庫連接,這是極大的佔服務器資源的事情,尤爲是內存。

若是你把你的表鎖上一段時間,好比30秒鐘,那麼對於一個有很高訪問量的站點來講,這30秒所積累的訪問進程/線程,數據庫連接,打開的文件數,可能不只僅會讓你泊WEB服務Crash,還可能會讓你的整臺服務器立刻掛了。

因此,若是你有一個大的處理,你定你必定把其拆分,使用 LIMIT 條件是一個好的方法。下面是一個示例:

複製代碼

while (1) { 
    //每次只作1000條 
    mysql_query("DELETE FROM logs WHERE log_date <= '2009-11-01' LIMIT 1000"); 
    if (mysql_affected_rows() == 0) { 
        // 沒得可刪了,退出! 
        break; 
    } 
    // 每次都要休息一下子 
    usleep(50000); 
}

複製代碼

 

where語句的優化

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

2.應儘可能避免在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’;

 

索引的優化

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

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

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

儘可能利用mysql索引排序

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

儘可能避勉innodb用很是大尺寸的字段做爲主鍵

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

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

做爲表關聯字段通常都須要創索引.

更新很是頻繁的字段不適合建立索引;

不會出如今 WHERE 子句中的字段不應建立索引.

選擇性過低的字段不適合單首創建索引

 

儘可能不要用子查詢

複製代碼

mysql> explain select uid_,count(*) from smember_6 where uid_ in (select uid_ from alluid) group by uid_;| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+--------------------+-----------+-------+---------------+---------+---------+------+----------+--------------------------+| 1 | PRIMARY | smember_6 | index | NULL | PRIMARY | 8 | NULL | 53431264 | Using where; Using index | | 2 | DEPENDENT SUBQUERY | alluid | ALL | NULL | NULL | NULL | NULL | 2448 | Using where |--優化後| mysql> explain select a.uid_,count(*) from smember_6 a,alluid b where a.uid_=b.uid_ group by uid_;+----+-------------+-------+------+---------------+---------+---------+------------+------+---------------------------------+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+-------+------+---------------+---------+---------+------------+------+---------------------------------+| 1 | SIMPLE | b | ALL | NULL | NULL | NULL | NULL | 2671 | Using temporary; Using filesort | | 1 | SIMPLE | a | ref | PRIMARY | PRIMARY | 4 | ssc.b.uid_ | 1 | Using index

複製代碼

 

Join的優化

若是你的應用程序有不少 JOIN 查詢,你應該確認兩個表中Join的字段是被建過索引的。這樣,MySQL內部會啓動爲你優化Join的SQL語句的機制。
並且,這些被用來Join的字段,應該是相同的類型的。例如:若是你要把 DECIMAL 字段和一個 INT 字段Join在一塊兒,MySQL就沒法使用它們的索引。對於那些STRING類型,還須要有相同的字符集才行。(兩個表的字符集有可能不同)

 

表的優化

儘量的使用 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 byte.」

 

固定長度的表會更快

若是表中的全部字段都是「固定長度」的,整個表會被認爲是 「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個多小時,由於裏面有一千六百萬條數據。

相關文章
相關標籤/搜索