mysql性能優化

數據庫的操做愈來愈成爲整個應用的性能瓶頸了,這點對於Web應用尤爲明顯。關於數據庫的性能,這並不僅是DBA才須要擔憂的事,而這更是我 們程序員須要去關注的事情php

1.爲查詢緩存優化你的查詢html

mysql> show variables like '%query_cache%'; 
(query_cache_type 爲 ON 表示已經開啓)
+------------------------------+----------+
| Variable_name                | Value    |
+------------------------------+----------+
| have_query_cache             | YES      |
| query_cache_limit            | 1048576  |
| query_cache_min_res_unit     | 4096     |
| query_cache_size             | 20971520 |
| query_cache_type             | ON       |
| query_cache_wlock_invalidate | OFF      |
+------------------------------+----------+

若是不是ON,修改配置文件以開啓查詢緩存:
> vi /etc/my.cnf
[mysqld]中添加:
query_cache_size = 20M  #緩存的大小
query_cache_type = ON   # 開啓緩存

優化提示:
若是Qcache_lowmem_prunes 值比較大,表示查詢緩存區大小設置過小,須要增大。
若是Qcache_free_blocks 較多,表示內存碎片較多,須要清理,flush query cache
根據我看的 《High PerformanceMySQL》中所述,關於query_cache_min_res_unit大小的調優
,書中給出了一個計算公式,能夠供調優設置參考:
query_cache_min_res_unit = (query_cache_size - Qcache_free_memory)/ Qcache_queries_in_cache

 

參考資料:http://blog.csdn.net/qq_27238185/article/details/54096069mysql

2.使用explain select查詢程序員

使用 EXPLAIN 關鍵字可讓你知道MySQL是如何處理你的SQL語句的。這能夠幫你分析你的查詢語句或是表結構的性能瓶頸。
EXPLAIN 的查詢結果還會告訴你你的索引主鍵被如何利用的,你的數據表是如何被搜索和排序的……等等,等等

eg: explain select * from user;
查看sql語句的性能:是否使用了索引、查詢涉及的條數

 

3.當只要一行數據時,使用limit 1算法

  加上 LIMIT 1 能夠增長性能。這樣同樣,MySQL數據庫引擎會在找到一條數據後中止搜索,而不是繼續日後查少下一條符合記錄的數據。sql

4.爲搜索字段加索引數據庫

  索引並不必定就是給主鍵或是惟一的字段。若是在你的表中,有某個字段你總要會常常用來作搜索,那麼,請爲其創建索引吧。緩存

5.在join表的時候,使用至關類型的例,並將其索引安全

  若是你的應用程序有不少 JOIN 查詢,你應該確認兩個表中Join的字段是被建過索引的。這樣,MySQL內部會啓動爲你優化Join的SQL語句的機制。服務器

6. 千萬不要order by rand();

  MySQL會不得 不去執行RAND()函數(很耗CPU時間),並且這是爲了每一行記錄去記行,而後再對其排序。就算是你用了Limit 1也無濟於事(由於要排序)

7.避免select * 

  從數據庫裏讀出越多的數據,那麼查詢就會變得越慢。而且,若是你的數據庫服務器和WEB服務器是兩臺獨立的服務器的話,這還會增長網絡傳輸的負載。

8. 永遠爲每張表設置一個ID

  咱們應該爲數據庫裏的每張表都設置一個ID作爲其主鍵,並且最好的是一個INT型的(推薦使用UNSIGNED),並設置上自動增長的AUTO_INCREMENT標誌。

  使用 VARCHAR 類型來當主鍵會使用得性能降低

9.使用enum而不是varchar

  ENUM 類型是很是快和緊湊的。在實際上,其保存的是 TINYINT,但其外表上顯示爲字符串。這樣一來,用這個字段來作一些選項列表變得至關的完美

10.從 PROCEDURE ANALYSE() 取得建議

  procedure analyse();會讓 MySQL 幫你去分析你的字段和其實際的數據,並會給你一些有用的建議。只有表中有實際的數據,這些建議纔會變得有用,由於要作一些大的決定是須要有數據做爲基礎的。

  

11.儘量的使用not null

  除非你有一個很特別的緣由去使用 NULL 值,你應該老是讓你的字段保持 NOT NULL。

  不要覺得 NULL 不須要空間,其須要額外的空間,而且,在你進行比較的時候,你的程序會更復雜。

12 prepared statements

  Prepared Statements很像存儲過程,是一種運行在後臺的SQL語句集合,咱們能夠從使用 prepared statements 得到不少好處,不管是性能問題仍是安全問題。

  在性能方面,當一個相同的查詢被使用屢次的時候,這會爲你帶來可觀的性能優點。你能夠給這些Prepared Statements定義一些參數,而MySQL只會解析一次

/ 建立 prepared statement  ; php 中的PDO
 if ($stmt = $mysqli->prepare("SELECT username FROM user WHERE state=?")) { 
    // 綁定參數 
    $stmt->bind_param("s", $state); 
    // 執行 
    $stmt->execute(); 
    // 綁定結果 
    $stmt->bind_result($username); 
    // 移動遊標 
    $stmt->fetch(); 
    printf("%s is from %s\n", $username, $state); 
    $stmt->close(); 
 } 

 

13 無緩衝的查詢

  正常的狀況下,當你在當你在你的腳本中執行一個SQL語句的時候,你的程序會停在那裏直到沒這個SQL語句返回,而後你的程序再往下繼續執行。你可使用無緩衝查詢來改變這個行爲。

  mysql_unbuffered_query() 發送一個SQL語句到MySQL而並不像mysql_query()同樣去自動fethch和緩存結果。這會至關節約不少可觀的內存,尤爲是那些會產生大 量結果的查詢語句,而且,你不須要等到全部的結果都返回,只須要第一行數據返回的時候,你就能夠開始立刻開始工做於查詢結果了。

  然而,這會有一些限制。由於你要麼把全部行都讀走,或是你要在進行下一次的查詢前調用 mysql_free_result() 清除結果。並且, mysql_num_rows() 或 mysql_data_seek() 將沒法使用。因此,是否使用無緩衝的查詢你須要仔細考慮。

14 把IP地址存成unsigned int 

  不少程序員都會建立一個 VARCHAR(15) 字段來存放字符串形式的IP而不是整形的IP。若是你用整形來存放,只須要4個字節,而且你能夠有定長的字段。並且,這會爲你帶來查詢上的優點,尤爲是當 你須要使用這樣的WHERE條件:IP between ip1 and ip2。

  咱們必須要使用UNSIGNED INT,由於 IP地址會使用整個32位的無符號整形。

  而你的查詢,你可使用 INET_ATON() 來把一個字符串IP轉成一個整形,並使用 INET_NTOA() 把一個整形轉成一個字符串IP。在PHP中,也有這樣的函數 ip2long() 和 long2ip()。

$r = "UPDATE users SET ip = INET_ATON('{$_SERVER['REMOTE_ADDR']}') WHERE user_id = $user_id"; 

 

15.固定長度的表會更快

若是表中的全部字段都是「固定長度」的,整個表會被認爲是 「static」 或 「fixed-length」。 例如,表中沒有以下類型的字段: VARCHAR,TEXT,BLOB。只要你包括了其中一個這些字段,那麼這個表就不是「固定長度靜態表」了,這樣,MySQL 引擎會用另外一種方法來處理。
固定長度的表會提升性能,由於MySQL搜尋得會更快一些,由於這些固定的長度是很容易計算下一個數據的偏移量的,因此讀取的天然也會很快。而若是字段不是定長的,那麼,每一次要找下一條的話,須要程序找到主鍵。
而且,固定長度的表也更容易被緩存和重建。不過,惟一的反作用是,固定長度的字段會浪費一些空間,由於定長的字段不管你用不用,他都是要分配那麼多的空間。
使用「垂直分割」技術(見下一條),你能夠分割你的表成爲兩個一個是定長的,一個則是不定長的。

 

16. 垂直分割

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

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

示例二: 你有一個叫 「last_login」 的字段,它會在每次用戶登陸時被更新。可是,每次更新時會致使該表的查詢緩存被清空。因此,你能夠把這個字段放到另外一個表中,這樣就不會影響你對用戶 ID,用戶名,用戶角色的不停地讀取了,由於查詢緩存會幫你增長不少性能。

另外,你須要注意的是,這些被分出去的字段所造成的表,你不會常常性地去Join他們,否則的話,這樣的性能會比不分割時還要差,並且,會是極數級的降低。

17 拆分大的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); 
 } 

 

18.越小的列會越快

對於大多數的數據庫引擎來講,硬盤操做多是最重大的瓶頸。因此,把你的數據變得緊湊會對這種狀況很是有幫助,由於這減小了對硬盤的訪問。

參看 MySQL 的文檔 Storage Requirements 查看全部的數據類型。

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

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

設置合理的字段大小

19.選擇正確的存儲引擎

在 MySQL 中有兩個存儲引擎 MyISAM 和 InnoDB,每一個引擎都有利有弊。酷殼之前文章《MySQL: InnoDB 仍是 MyISAM?》討論和這個事情。

MyISAM 適合於一些須要大量查詢的應用,但其對於有大量寫操做並非很好。甚至你只是須要update一個字段,整個表都會被鎖起來,而別的進程,就算是讀進程都 沒法操做直到讀操做完成。另外,MyISAM 對於 SELECT COUNT(*) 這類的計算是超快無比的。

InnoDB 的趨勢會是一個很是複雜的存儲引擎,對於一些小的應用,它會比 MyISAM 還慢。他是它支持「行鎖」 ,因而在寫操做比較多的時候,會更優秀。而且,他還支持更多的高級應用,好比:事務。

下面是MySQL的手冊

target=」_blank」MyISAM Storage Engine

InnoDB Storage Engine

爲何MyISAM會比Innodb的查詢速度快?

INNODB在作SELECT的時候,要維護的東西比MYISAM引擎多不少:
1)數據塊,INNODB要緩存,MYISAM只緩存索引塊,  這中間還有換進換出的減小;
 

2)innodb尋址要映射到塊,再到行,MYISAM記錄的直接是文件的OFFSET,定位比INNODB要快

3)INNODB還須要維護MVCC一致;雖然你的場景沒有,但他仍是須要去檢查和維護
MVCC (Multi-Version Concurrency Control)多版本併發控制 

註釋:
InnoDB:經過爲每一行記錄添加兩個額外的隱藏的值來實現MVCC,這兩個值一個記錄這行數據什麼時候被建立,另一個記錄這行數據什麼時候過時(或者被刪除)。可是InnoDB並不存儲這些事件發生時的實際時間,相反它只存儲這些事件發生時的系統版本號。
這是一個隨着事務的建立而不斷增加的數字。每一個事務在事務開始時會記錄它本身的系統版本號。每一個查詢必須去檢查每行數據的版本號與事務的版本號是否相同。讓咱們來看看當隔離級別是REPEATABLEREAD時這種策略是如何應用到特定的操做的:   SELECT InnoDB必須每行數據來保證它符合兩個條件:   
1、InnoDB必須找到一個行的版本,它至少要和事務的版本同樣老(也即它的版本號不大於事務的版本號)。這保證了無論是事務開始以前,或者事務建立時,或者修改了這行數據的時候,這行數據是存在的。   二、這行數據的刪除版本必須是未定義的或者比事務版本要大。這能夠保證在事務開始以前這行數據沒有被刪除

 

20 使用一個對象關係映射器(Object Relational Mapper)

使用 ORM (Object Relational Mapper),你可以得到可靠的性能增漲。一個ORM能夠作的全部事情,也能被手動的編寫出來。可是,這須要一個高級專家。

ORM 的最重要的是「Lazy Loading」,也就是說,只有在須要的去取值的時候纔會去真正的去作。但你也須要當心這種機制的反作用,由於這頗有可能會由於要去建立不少不少小的查詢反而會下降性能。

ORM 還能夠把你的SQL語句打包成一個事務,這會比單獨執行他們快得多得多。

目前,我的最喜歡的PHP的ORM是:Doctrine。

21.當心「永久連接」

「永久連接」的目的是用來減小從新建立MySQL連接的次數。當一個連接被建立了,它會永遠處在鏈接的狀態,就算是數據庫操做已經結束了。並且,自 從咱們的Apache開始重用它的子進程後——也就是說,下一次的HTTP請求會重用Apache的子進程,並重用相同的 MySQL 連接。

PHP手冊:mysql_pconnect()

在理論上來講,這聽起來很是的不錯。可是從我的經驗(也是大多數人的)上來講,這個功能製造出來的麻煩事更多。由於,你只有有限的連接數,內存問題,文件句柄數,等等。

並且,Apache 運行在極端並行的環境中,會建立不少不少的了進程。這就是爲何這種「永久連接」的機制工做地很差的緣由。在你決定要使用「永久連接」以前,你須要好好地考慮一下你的整個系統的架構。

 

以上內容的參考資料:http://database.51cto.com/art/201505/476659.htm

22.索引的優化

1、索引優化(有關索引詳解可參看博客http://blog.csdn.net/zhangliangzi/article/details/51366345)
1、合理使用索引,在常常查詢而不常常增刪改操做的字段加索引,一個表上的索引不該該超過6個。
2、Order by與group by後應直接使用字段,並且字段應該是索引字段。
3、索引字段長度應較短而長度固定。
4、索引字段重複不能過多。
5、Hash索引與BTree索引區別(MyISAM與InnoDB不支持Hash索引)
  (1)、BTree索引使用多路搜索樹的數據結構,能夠減小定位的中間過程;綜合效率較高,默認使用的索引。
  (2)、Hash索引使用Hash算法構建索引;精確的等值查詢一次定位,效率極高,但特別不適合範圍查詢;使用Hash的複合索引是把複合索引鍵共同計算hash值,故不能單獨使用。

6、會致使引擎放棄使用索引,改成進行全表的幾種狀況,都要在開發中儘可能避免出現!
(1)、where子句中使用like關鍵字時,前置百分號會致使索引失效(起始字符不肯定都會失效)。如:select id from test where name like "%吉坤"。
(2)、where子句中使用is null或is not null時,由於null值會被自動從索引中排除,索引通常不會創建在有空值的列上。
(3)、where子句中使用or關鍵字時,or左右字段若是存在一個沒有索引,有索引字段也會失效;並且即便都有索引,由於兩者的索引存儲順序並不一致,效率還不如順序全表掃描,這時引擎有可能放棄使用索引,因此要慎用or。
(4)、where子句中使用in或not in關鍵字時,會致使全表掃描,能使用exists或between and替代就不使用in。
(5)、where子句中使用!=操做符時,將放棄使用索引,由於範圍不肯定,使用索引效率不高,會被引擎自動改成全表掃描;
(6)、where子句中應儘可能避免對索引字段操做(表達式操做或函數操做),好比select id from test where num/2 = 100應改成num = 200。
(7)、在使用複合索引時,查詢時必須使用到索引的第一個字段,不然索引失效;而且應儘可能讓字段順序與索引順序一致。
(8)、查詢時必須使用正確的數據類型。數據庫包含了自動了類型轉換,好比純數字賦值給字符串字段時能夠被自動轉換,但若是查詢時不加引號查詢,會致使引擎忽略索引。

 

23. 表結構的優化

1、設計符合第三範式的表結構。
2、儘可能使用數字型字段,提升數據比對效率。
3、對定長、MD5哈希碼、長度較短的字段使用char類型,提升效率;對邊長並且可能較長字段使用varchar類型,節約內存。
四、適當的進行水平分割與垂直分割,好比當表列數過多時,就將一部分列移出到另外一張表中。

 

24. 分析慢查詢

首先,不管進行何種優化,開啓慢查詢都算是前置條件。慢查詢機制,將記錄過慢的查詢語句(事件),從而爲DB維護人員提供優化目標。

查看是否開啓:show variables like 'slow_query_log'

開啓慢查詢:

[mysqld]
port= 3306
 
slow-query-log=1 # 慢查詢:確認開啓
slow-query-log-file="D:/xampp/mysql/log/mysql-slow.log" # 慢查詢:日誌文件及路徑
long_query_time = 5 # 慢查詢:指定超過5s仍未完成的語句,爲執行過慢的語句


參考資料:http://www.cnblogs.com/luyucheng/p/6265594.html

 

25.sql語句的優化

參考資料:http://database.51cto.com/art/201407/445934.htm

 

 

參考資料:http://blog.csdn.net/zhangliangzi/article/details/52329355

相關文章
相關標籤/搜索