① 優化MySQL所在服務器內核(此優化通常由運維人員完成)。mysql
② 對MySQL配置參數進行優化(my.cnf)此優化須要進行壓力測試來進行參數調整。程序員
③ 對SQL語句以及表優化。sql
1:MySQL 默認的最大鏈接數爲 100,能夠在 mysql 客戶端使用如下命令查看
mysql> show variables like 'max_connections';
2:查看當前訪問Mysql的線程
mysql> show processlist;
3:設置最大鏈接數
mysql>set globle max_connections = 5000;
最大可設置16384,超過沒用
4:查看當前被使用的connections
mysql>show globle status like 'max_user_connections'數據庫
① 爲查詢緩存優化查詢緩存
② EXPLAIN 咱們的SELECT查詢(能夠查看執行的行數)安全
③ 當只要一行數據時使用LIMIT 1性能優化
④ 爲搜索字段創建索引服務器
⑤ 在Join表的時候使用至關類型的列,並將其索引網絡
⑥ 千萬不要 ORDER BY RAND ()數據結構
⑦ 避免SELECT *
⑧ 永遠爲每張表設置一個ID
⑨ 可使用ENUM 而不要VARCHAR
⑩ 儘量的使用NOT NULL
⑪ 固定長度的表會更快
⑫ 垂直分割
⑬ 拆分打的DELETE或INSERT語句
⑭ 越小的列會越快
⑮ 選擇正確的存儲引擎
⑯ 當心 "永久連接"
具體描述以下:
(一) 使用查詢緩存優化查詢
大多數的MySQL服務器都開啓了查詢緩存。這是提升性能最有效的方法之一,並且這是被MySQL引擎處理的。當有不少相同的查詢被執行了屢次的時候,這些查詢結果會被放入一個緩存中,這樣後續的相同查詢就不用操做而直接訪問緩存結果了。
這裏最主要的問題是,對於咱們程序員來講,這個事情是很容易被忽略的。由於咱們某些查詢語句會讓MySQL不使用緩存,示例以下:
1:SELECT username FROM user WHERE signup_date >= CURDATE()
2:SELECT username FROM user WHERE signup_date >= '2014-06-24‘
上面兩條SQL語句的差異就是 CURDATE() ,MySQL的查詢緩存對這個函數不起做用。因此,像 NOW() 和 RAND() 或是其它的諸如此類的SQL函數都不會開啓查詢緩存,由於這些函數的返回是會不定的易變的。因此,你所須要的就是用一個變量來代替MySQL的函數,從而開啓緩存。
(二) 使用EXPLAIN關鍵字檢測查詢
使用EXPLAIN關鍵字可使咱們知道MySQL是如何處理SQL語句的,這樣能夠幫助咱們分析咱們的查詢語句或是表結構的性能瓶頸;EXPLAIN的查詢結果還會告訴咱們索引主鍵是如何被利用的,數據表是如何被被搜索或排序的....等等。語法格式是:EXPLAIN +SELECT語句;
咱們能夠看到,前一個結果顯示搜索了 7883 行,然後一個只是搜索了兩個表的 9 和 16 行。查看rows列可讓咱們找到潛在的性能問題。
(三)當只要一行數據時使用LIMIT 1
加上LIMIT 1能夠增長性能。MySQL數據庫引擎會在查找到一條數據後中止搜索,而不是繼續日後查詢下一條符合條件的數據記錄。
(四)爲搜索字段創建索引
索引不必定就是給主鍵或者是惟一的字段,若是在表中,有某個字段常常用來作搜索,須要將其創建索引。
索引的有關操做以下:
1.建立索引
在執行CREATE TABLE語句時能夠建立索引,也能夠單獨用CREATE INDEX或ALTER TABLE來爲表增長索引。
1.1> ALTER TABLE
ALTER TABLE 用來建立普通索引、惟一索引、主鍵索引和全文索引
ALTER TABLE table_name ADD INDEX index_name (column_list);
ALTER TABLE table_name ADD UNIQUE (column_list);
ALTER TABLE table_name ADD PRIMARY KEY (column_list);
ALTER TABLE table_name ADD FULLTEXT (column_list);
其中table_name是要增長索引名的表名,column_list指出對哪些列列進行索引,多列時各列之間使用半角逗號隔開。索引名index_name是可選的,若是不指定索引名稱,MySQL將根據第一個索引列自動指定索引名稱,另外,ALTER TABLE容許在單個語句中更改多個表,所以能夠在同時建立多個索引。
1.2> CREATE INDEX
CREATE INDEX可對錶增長普通索引或UNIQUE索引以及全文索引,可是不能夠對錶增長主鍵索引
CREATE INDEX index_name ON table_name (column_list);
CREATE UNIQUE index_name ON table_name (column_list);
CREATE FULLTEXT index_name ON table_name (column_list);
table_name、index_name和column_list具備與ALTER TABLE語句中相同的含義,索引名必須指定。另外,不能用CREATE INDEX語句建立PRIMARY KEY索引。
2.索引類型
普通索引INDEX:適用於name、email等通常屬性
惟一索引UNIQUE:與普通索引相似,不一樣的是惟一索引要求索引字段值在表中是惟一的,這一點和主鍵索引相似,可是不一樣的是,惟一索引容許有空值。惟一索引通常適用於身份證號碼、用戶帳號等不容許有重複的屬性字段上。
主鍵索引:其實就是主鍵,通常在建表時就指定了,不須要額外添加。
全文檢索:只適用於VARCHAR和Text類型的字段。
注意:全文索引和普通索引是有很大區別的,若是創建的是普通索引,通常會使用like進行模糊查詢,只會對查詢內容前一部分有效,即只對前面不使用通配符的查詢有效,若是先後都有通配符,普通索引將不會起做用。對於全文索引而言在查詢時有本身獨特的匹配方式,例如咱們在對一篇文章的標題和內容進行全文索引時:
ALTER TABLE article ADD FULLTEXT ('title', 'content'); 在進行檢索時就須要使用以下的語法進行檢索:
SELECT * FROM article WHERE MATCH('title', 'content') AGAINST ('查詢字符串');
在使用全文檢索時的注意事項:
MySql自帶的全文索引只能用於數據庫引擎爲MYISAM的數據表,若是是其餘數據引擎,則全文索引不會生效。此外,MySql自帶的全文索引只能對英文進行全文檢索,目前沒法對中文進行全文檢索。若是須要對包含中文在內的文本數據進行全文檢索,咱們須要採用Sphinx(斯芬克斯)/Coreseek技術來處理中文。另外使用MySql自帶的全文索引時,若是查詢字符串的長度太短將沒法獲得指望的搜索結果。MySql全文索引所能找到的詞默認最小長度爲4個字符。另外,若是查詢的字符串包含中止詞,那麼該中止詞將會被忽略。
3.組合索引
組合索引又稱多列索引,就是創建索引時指定多個字段屬性。有點相似於字典目錄,好比查詢 'guo' 這個拼音的字時,首先查找g字母,而後在g的檢索範圍內查詢第二個字母爲u的列表,最後在u的範圍內查找最後一個字母爲o的字。好比組合索引(a,b,c),abc都是排好序的,在任意一段a的下面b都是排好序的,任何一段b下面c都是排好序的
組合索引的生效原則是 從前日後依次使用生效,若是中間某個索引沒有使用,那麼斷點前面的索引部分起做用,斷點後面的索引沒有起做用;
形成斷點的緣由:
前邊的任意一個索引沒有參與查詢,後邊的所有不生效。
前邊的任意一個索引字段參與的是範圍查詢,後面的不會生效。
斷點跟索引字字段在SQL語句中的位置先後無關,只與是否存在有關。在網上找到了很好的示例:
好比:
[sql] view plain copy
(a,b,c) 三個列上加了聯合索引(是聯合索引 不是在每一個列上單獨加索引)而是創建了a,(a,b),(a,b,c)三個索引,另外(a,b,c)多列索引和 (a,c,b)是不同的。
具體實例能夠說明:
[sql] view plain copy
注意:在查詢時,MYSQL只能使用一個索引,若是創建的是多個單列的普通索引,在查詢時會根據查詢的索引字段,從中選擇一個限制最嚴格的單例索引進行查詢。別的索引都不會生效。
4.查看索引
mysql> show index from tblname;
mysql> show keys from tblname;
5.刪除索引
刪除索引的mysql格式 :DORP INDEX IndexName ON tab_name;
注意:不能使用索引的狀況
對於普通索引而言 在使用like進行通配符模糊查詢時,若是首尾之間都使用了通配符,索引時無效的。
假設查詢內容的關鍵詞爲'abc'
SELECT * FROM tab_name WHERE index_column LIKE 'abc%'; #索引是有效的
SELECT * FROM tab_name WHERE index_column LIKE '%abc'; #索引是無效的
SELECT * FROM tab_name WHERE index_column LIKE '%cba'; #索引是有效的
SELECT * FROM tab_name WHERE index_column LIKE '%abc%'; #索引是無效的
當檢索的字段內容比較大並且檢索內容先後部分都不肯定的狀況下,能夠改成全文索引,並使用特定的檢索方式。
(五)在join表的時候使用至關類型的列,並將其索引
若是在程序中有不少JOIN查詢,應該保證兩個表中join的字段時被創建過索引的。這樣MySQL顳部會啓動優化JOIN的SQL語句的機制。注意:這些被用來JOIN的字段,應該是相同類型的。例如:若是要把 DECIMAL 字段和一個 INT 字段Join在一塊兒,MySQL就沒法使用它們的索引。對於那些STRING類型,還須要有相同的字符集才行。(兩個表的字符集有可能不同)
例如:
SELECT company_name FROM users LEFT JOIN companies ON (users.state = companies.state) WHERE users.id = 「user_id」
兩個 state 字段應該是被建過索引的,並且應該是至關的類型,相同的字符集。
(六)切記不要使用ORDER BY RAND()
若是你真的想把返回的數據行打亂了,你有N種方法能夠達到這個目的。這樣使用只讓你的數據庫的性能呈指數級的降低。這裏的問題是:MySQL會不得不去執行RAND()函數(很耗CPU時間),並且這是爲了每一行記錄去記行,而後再對其排序。就算是你用了Limit 1也無濟於事(由於要排序)
(七)避免使用SELECT *
從數據庫裏讀出越多的數據,那麼查詢就會變得越慢。而且,若是咱們的數據庫服務器和WEB服務器是兩臺獨立的服務器的話,這還會增長網絡傳輸的負載。 因此,咱們應該養成一個須要什麼就取什麼的好的習慣。
Hibernate性能方面就會差,它不用*,但它將整個表的全部字段全查出來
優勢:開發速度快
(八)永遠爲每張表設置一個ID主鍵
咱們應該爲數據庫裏的每張表都設置一個ID作爲其主鍵,並且最好的是一個INT型的(推薦使用UNSIGNED),並設置上自動增長的 AUTO_INCREMENT標誌。 就算是咱們 users 表有一個主鍵叫 「email」的字段,咱們也別讓它成爲主鍵。使用 VARCHAR 類型來當主鍵會使用得性能降低。另外,在咱們的程序中,咱們應該使用表的ID來構造咱們的數據結構。 並且,在MySQL數據引擎下,還有一些操做須要使用主鍵,在這些狀況下,主鍵的性能和設置變得很是重要,好比,集羣,分區…… 在這裏,只有一個狀況是例外,那就是「關聯表」的「外鍵」,也就是說,這個表的主鍵,經過若干個別的表的主鍵構成。咱們把這個狀況叫作「外鍵」。好比:有一個「學生表」有學生的ID,有一個「課程表」有課程ID,那麼,「成績表」就是「關聯表」了,其關聯了學生表和課程表,在成績表中,學生ID和課程ID叫「外鍵」其共同組成主鍵。
(九)使用ENUM而不是VARCHAR
ENUM 類型是很是快和緊湊的。在實際上,其保存的是 TINYINT,但其外表上顯示爲字符串。這樣一來,用這個字段來作一些選項列表變得至關的完美。 若是咱們有一個字段,好比「性別」,「國家」,「民族」,「狀態」或「部門」,咱們知道這些字段的取值是有限並且固定的,那麼,咱們應該使用 ENUM 而不是 VARCHAR。
(十)儘量的不要賦值爲NULL
若是不是特殊狀況,儘量的不要使用NULL。在MYSQL中對於INT類型而言,EMPTY是0,而NULL是空值。而在Oracle中 NULL和EMPTY的字符串是同樣的。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搜尋得會更快一些,由於這些固定的長度是很容易計算下一個數據的偏移量的,因此讀取的天然也會很快。而若是字段不是定長的,那麼,每一次要找下一條的話,須要程序找到主鍵。 而且,固定長度的表也更容易被緩存和重建。不過,惟一的反作用是,固定長度的字段會浪費一些空間,由於定長的字段不管咱們用不用,他都是要分配那麼多的空間。另外在取出值的時候要使用trim去除空格
(十二)垂直分割
「垂直分割」是一種把數據庫中的表按列變成幾張表的方法,這樣能夠下降表的複雜度和字段的數目,從而達到優化的目的。
(十三)拆分大的DELETE或INSERT
若是咱們須要在一個在線的網站上去執行一個大的 DELETE 或 INSERT 查詢,咱們須要很是當心,要避免咱們的操做讓咱們的整個網站中止相應。由於這兩個操做是會鎖表的,表一鎖住了,別的操做都進不來了。Apache 會有不少的子進程或線程。因此,其工做起來至關有效率,而咱們的服務器也不但願有太多的子進程,線程和數據庫連接,這是極大的佔服務器資源的事情,尤爲是內存。若是咱們把咱們的表鎖上一段時間,好比30秒鐘,那麼對於一個有很高訪問量的站點來講,這30秒所積累的訪問進程/線程,數據庫連接,打開的文件數,可能不只僅會讓咱們的WEB服務Crash,還可能會讓咱們的整臺服務器立刻掛了。因此在使用時使用LIMIT 控制數量操做記錄的數量。
(十四)越小的列會越快
對於大多數的數據庫引擎來講,硬盤操做多是最重大的瓶頸。因此,把咱們的數據變得緊湊會對這種狀況很是有幫助,由於這減小了對硬盤的訪問。 參看 MySQL 的文檔 Storage Requirements 查看全部的數據類型。 若是一個表只會有幾列罷了(好比說字典表,配置表),那麼,咱們就沒有理由使用 INT 來作主鍵,使用 MEDIUMINT, SMALLINT 或是更小的 TINYINT 會更經濟一些。若是咱們不須要記錄時間,使用 DATE 要比 DATETIME 好得多。
(十五)選擇正確的存儲引擎
在MYSQL中有兩個存儲引擎MyISAM和InnoDB,每一個引擎都有利有弊。
MyISAM適合於一些須要大量查詢的應用,可是對於大量寫操做的支持不是很好。甚至一個update語句就會進行鎖表操做,這時讀取這張表的全部進程都沒法進行操做直至寫操做完成。另外MyISAM對於SELECT COUNT(*)這類的計算是超快無比的。InnoDB 的趨勢會是一個很是複雜的存儲引擎,對於一些小的應用,它會比 MyISAM 還慢。它支持「行鎖」 ,因而在寫操做比較多的時候,會更優秀。而且,他還支持更多的高級應用,好比:事務。
MyISAM是MYSQL5.5版本之前默認的存儲引擎,基於傳統的ISAM類型,支持B-Tree,全文檢索,可是不是事務安全的,並且不支持外鍵。不具備原子性。支持鎖表。
InnoDB是事務型引擎,支持ACID事務(實現4種事務隔離機制)、回滾、崩潰恢復能力、行鎖。以及提供與Oracle一致的不加鎖的讀取方式。InnoDB存儲它的表和索引在一個表空間中,表空間能夠包含多個文件。
MyISAM和InnoDB比較,以下圖所示:
對於Linux版本的MYSQL 配置文件在 /etc/my.cnf中
在5.5以後默認的存儲引擎是INNODB
能夠單獨進行修改也能夠在建立表時修改:
ALTER TABLE tab_name ENGINE INNODB;
(十六)當心永久連接
「永久連接」的目的是用來減小從新建立MySQL連接的次數。當一個連接被建立了,它會永遠處在鏈接的狀態,就算是數據庫操做已經結束了。並且,自從咱們的Apache開始重用它的子進程後——也就是說,下一次的HTTP請求會重用Apache的子進程,並重用相同的 MySQL 連接。 並且,Apache 運行在極端並行的環境中,會建立不少不少的了進程。這就是爲何這種「永久連接」的機制工做地很差的緣由。在咱們決定要使用「永久連接」以前,咱們須要好好地考慮一下咱們的整個系統的架構。