Mysql數據庫調優和性能優化的21條最佳實踐

做者:andyaophp

原文link: http://andyao.iteye.com/admin/show/144033java

轉載請留名mysql

1. 簡介 
在Web應用程序體系架構中,數據持久層(一般是一個關係數據庫)是關鍵的核心部分,它對系統的性能有很是重要的影響。MySQL是目前使用最多的開源數據庫,可是MySQL數據庫的默認設置性能很是的差,僅僅是一個玩具數據庫。所以在產品中使用MySQL數據庫必須進行必要的優化。
優化是一個複雜的任務,本文描述MySQL相關的數據庫設計和查詢優化,服務器端優化,存儲引擎優化。

2. 數據庫設計和查詢優化 
在MySQL Server性能調優中,首先要考慮的就是Database Schema設計,這一點是很是重要的。一個糟糕的Schema設計即便在性能調優的MySQL Server上運行,也會表現出不好的性能;和Schema類似,查詢語句的設計也會影響MySQL的性能,應該避免寫出低效的SQL查詢。這一節將詳細討論這兩方面的優化。

2.1 Schema Design 
Schema的優化取決於將要運行什麼樣的query,不一樣的query會有不一樣的Schema優化方案。2.2節將介紹Query Design的優化。Schema設計一樣受到預期數據集大小的影響。Schema設計時主要考慮:標準化,數據類型,索引。

2.1.1 標準化 

標準化是在數據庫中組織數據的過程。其中包括,根據設計規則建立表並在這些表間創建關係;經過取消冗餘度與不一致相關性,該設計規則能夠同時保護數據並提升數據的靈活性。一般數據庫標準化是讓數據庫設計符合某一級別的範式,一般知足第三範式便可。也有第四範式(也稱爲 Boyce Codd範式,BCNF))與第五範式存在,可是在實際設計中不多考慮。忽視這些規則可能使得數據庫的設計不太完美,但這不該影響功能。
標準化的特色:c++

1) 全部的「對象」都在它本身的table中,沒有冗餘。
2) 數據庫一般由E-R圖生成。
3) 簡潔,更新屬性一般只須要更新不多的記錄。
4) Join操做比較耗時。
5) Select,sort優化措施比較少。
6) 適用於OLTP應用。

非標準化的特色:程序員

1) 在一張表中存儲不少數據,數據冗餘。
2) 更新數據開銷很大,更新一個屬性可能會更新不少表,不少記錄。
3) 在刪除數據是有可能丟失數據。
4) Select,order有不少優化的選擇。
5) 適用於DSS應用。


標準化和非標準化都有各自的優缺點,一般在一個數據庫設計中能夠混合使用,一部分表格標準化,一部分表格保留一些冗餘數據:sql

1) 對OLTP使用標準化,對DSS使用非標準化
2) 使用物化視圖。MySQL不直接支持該數據庫特性,可是能夠用MyISAM表代替。
3) 冗餘一些數據在表格中,例如將ref_id和name存在同一張表中。可是要注意更新問題。
4) 對於一些簡單的對象,直接使用value做爲建。例如IP address等
5) Reference by PRIMARY/UNIQUE KEY。MySQL能夠優化這種操做,例如:

java 代碼數據庫

  1. select city_name緩存

  2. from city,state安全

  3. where state_id=state.id and state.code=‘CA’」 converted to 「select city_name from city where state_id=12性能優化


2.1.2 數據類型 
最基本的優化之一就是使表在磁盤上佔據的空間儘量小。這能帶來性能很是大的提高,由於數據小,磁盤讀入較快,而且在查詢過程當中表內容被處理所佔用的內存更少。同時,在更小的列上建索引,索引也會佔用更少的資源。
可使用下面的技術可使表的性能更好而且使存儲空間最小:

1) 使用正確合適的類型,不要將數字存儲爲字符串。
2) 儘量地使用最有效(最小)的數據類型。MySQL有不少節省磁盤空間和內存的專業化類型。
3) 儘量使用較小的整數類型使表更小。例如,MEDIUMINT常常比INT好一些,由於MEDIUMINT列使用的空間要少25%。
4) 若是可能,聲明列爲NOT NULL。它使任何事情更快並且每列能夠節省一位。注意若是在應用程序中確實須要NULL,應該毫無疑問使用它,只是避免 默認地在全部列上有它。
5) 對於MyISAM表,若是沒有任何變長列(VARCHAR、TEXT或BLOB列),使用固定尺寸的記錄格式。這比較快可是不幸地可能會浪費一些空間。即便你已經用CREATE選項讓VARCHAR列ROW_FORMAT=fixed,也能夠提示想使用固定長度的行。
6) 使用sample character set,例如latin1。儘可能少使用utf-8,由於utf-8佔用的空間是latin1的3倍。能夠在不須要使用utf-8的字段上面使用latin1,例如mail,url等。


2.1.3 索引 
全部MySQL列類型能夠被索引。對相關列使用索引是提升SELECT操做性能的最佳途徑。使用索引應該注意如下幾點:

1) MySQL只會使用前綴,例如key(a, b) …where b=5 將使用不到索引。
2) 要選擇性的使用索引。在變化不多的列上使用索引並非很好,例如性別列。
3) 在Unique列上定義Unique index。
4) 避免創建使用不到的索引。
5) 在Btree index中(InnoDB使用Btree),能夠在須要排序的列上創建索引。
6) 避免重複的索引。
7) 避免在已有索引的前綴上創建索引。例如:若是存在index(a,b)則去掉index(a)。
8) 控制單個索引的長度。使用key(name(8))在數據的前面幾個字符創建索引。
9) 越是短的鍵值越好,最好使用integer。
10) 在查詢中要使用到索引(使用explain查看),能夠減小讀磁盤的次數,加速讀取數據。
11) 相近的鍵值比隨機好。Auto_increment就比uuid好。
12) Optimize table能夠壓縮和排序index,注意不要頻繁運行。
13) Analyze table能夠更新數據。

2.2 Designing queries 
查詢語句的優化是一個Case by case的問題,不一樣的sql有不一樣的優化方案,在這裏我只列出一些通用的技巧。

1) 在有index的狀況下,儘可能保證查詢使用了正確的index。可使用EXPLAIN select …查看結果,分析查詢。
2) 查詢時使用匹配的類型。例如select * from a where id=5, 若是這裏id是字符類型,同時有index,這條查詢則使用不到index,會作全表掃描,速度會很慢。正確的應該是 … where id=」5」 ,加上引號代表類型是字符。
3) 使用--log-slow-queries –long-query-time=2查看查詢比較慢的語句。而後使用explain分析查詢,作出優化。

3. 服務器端優化
3.1 MySQL安裝 
MySQL有不少發行版本,最好使用MySQL AB發佈的二進制版本。也能夠下載源代碼進行編譯安裝,可是編譯器和類庫的一些bug可能會使編譯完成的MySQL存在潛在的問題。
若是安裝MySQL的服務器使用的是Intel公司的處理器,可使用intel c++編譯的版本,在Linux World2005的一篇PPT中提到,使用intel C++編譯器編譯的MySQL查詢速度比正常版本快30%左右。Intel c++編譯版本能夠在MySQL官方網站下載。

3.2 服務器設置優化 
MySQL默認的設置性能不好,因此要作一些參數的調整。這一節介紹一些通用的參數調整,不涉及具體的存儲引擎(主要指MyISAM,InnoDB,相關優化在4中介紹)。

--character-set:若是是單一語言使用簡單的character set例如latin1。儘可能少用Utf-8,utf-8佔用空間較多。
--memlock:鎖定MySQL只能運行在內存中,避免swapping,可是若是內存不夠時有可能出現錯誤。
--max_allowed_packet:要足夠大,以適應比較大的SQL查詢,對性能沒有太大影響,主要是避免出現packet錯誤。
--max_connections:server容許的最大鏈接。太大的話會出現out of memory。
--table_cache:MySQL在同一時間保持打開的table的數量。打開table開銷比較大。通常設置爲512。
--query_cache_size: 用於緩存查詢的內存大小。
--datadir:mysql存放數據的根目錄,和安裝文件分開在不一樣的磁盤能夠提升一點性能。

4. 存儲引擎優化 
MySQL支持不一樣的存儲引擎,主要使用的有MyISAM和InnoDB。

4.1 MyISAM 
MyISAM管理非事務表。它提供高速存儲和檢索,以及全文搜索能力。MyISAM在全部MySQL配置裏被支持,它是默認的存儲引擎,除非配置MySQL默認使用另一個引擎。

4.1.1 MyISAM特性 
4.1.1.1 MyISAM Properties

1) 不支持事務,宕機會破壞表
2) 使用較小的內存和磁盤空間
3) 基於表的鎖,併發更新數據會出現嚴重性能問題
4) MySQL只緩存Index,數據由OS緩存

4.1.1.2 Typical MyISAM usages

1) 日誌系統
2) 只讀或者絕大部分是讀操做的應用
3) 全表掃描
4) 批量導入數據
5) 沒有事務的低併發讀/寫

4.1.2 MyISAM優化要點

1) 聲明列爲NOT NULL,能夠減小磁盤存儲。
2) 使用optimize table作碎片整理,回收空閒空間。注意僅僅在很是大的數據變化後運行。
3) Deleting/updating/adding大量數據的時候禁止使用index。使用ALTER TABLE t DISABLE KEYS。
4) 設置myisam_max_[extra]_sort_file_size足夠大,能夠顯著提升repair table的速度。

4.1.3 MyISAM Table Locks

1) 避免併發insert,update。
2) 可使用insert delayed,可是有可能丟失數據。
3) 優化查詢語句。
4) 水平分區。
5) 垂直分區。
6) 若是都不起做用,使用InnoDB。

4.1.4 MyISAM Key Cache

1) 設置key_buffer_size variable。MyISAN最主要的cache設置,用於緩存MyISAM表格的index數據,該參數只對MyISAM有影響。一般在只使用MyISAM的Server中設置25-33%的內存大小。
2) 可使用幾個不一樣的Key Caches(對一些hot data)。
a) SET GLOBAL test.key_buffer_size=512*1024;
b) CACHE INDEX t1.i1, t2.i1, t3 IN test;
2) Preload index到Cache中能夠提升查詢速度。由於preloading index是順序的,因此很是快。
a) LOAD INDEX INTO CACHE t1, t2 IGNORE LEAVES;


4.2 InnoDB
InnoDB給MySQL提供了具備提交,回滾和崩潰恢復能力的事務安全(ACID兼容)存儲引擎。InnoDB提供row level lock,而且也在SELECT語句提供一個Oracle風格一致的非鎖定讀。這些特點增長了多用戶部署和性能。沒有在InnoDB中擴大鎖定的須要,由於在InnoDB中row level lock適合很是小的空間。InnoDB也支持FOREIGN KEY約束。在SQL查詢中,你能夠自由地將InnoDB類型的表與其它MySQL的表的類型混合起來,甚至在同一個查詢中也能夠混合。
InnoDB是爲在處理巨大數據量時得到最大性能而設計的。它的CPU使用效率很是高。
InnoDB存儲引擎已經徹底與MySQL服務器整合,InnoDB存儲引擎爲在內存中緩存數據和索引而維持它本身的緩衝池。 InnoDB存儲它的表&索引在一個表空間中,表空間能夠包含數個文件(或原始磁盤分區)。這與MyISAM表不一樣,好比在MyISAM表中每一個表被存在分離的文件中。InnoDB 表能夠是任何大小,即便在文件尺寸被限制爲2GB的操做系統上。
許多須要高性能的大型數據庫站點上使用了InnoDB引擎。著名的Internet新聞站點Slashdot.org運行在InnoDB上。 Mytrix, Inc.在InnoDB上存儲超過1TB的數據,還有一些其它站點在InnoDB上處理平均每秒800次插入/更新的負荷。
4.2.1 InnoDB特性 
4.2.1.1 InnoDB Properties

1) 支持事務,ACID,外鍵。
2) Row level locks。 
3) 支持不一樣的隔離級別。
4) 和MyISAM相比須要較多的內存和磁盤空間。
5) 沒有鍵壓縮。
6) 數據和索引都緩存在內存hash表中。

4.2.1.2 InnoDB Good For

1) 須要事務的應用。
2) 高併發的應用。
3) 自動恢復。
4) 較快速的基於主鍵的操做。

4.2.2 InnoDB優化要點

1) 儘可能使用short,integer的主鍵。
2) Load/Insert數據時按主鍵順序。若是數據沒有按主鍵排序,先排序而後再進行數據庫操做。
3) 在Load數據是爲設置SET UNIQUE_CHECKS=0,SET FOREIGN_KEY_CHECKS=0,能夠避免外鍵和惟一性約束檢查的開銷。
4) 使用prefix keys。由於InnoDB沒有key壓縮功能。

4.2.3 InnoDB服務器端設定

innodb_buffer_pool_size:這是InnoDB最重要的設置,對InnoDB性能有決定性的影響。默認的設置只有8M,因此默認的數據庫設置下面InnoDB性能不好。在只有InnoDB存儲引擎的數據庫服務器上面,能夠設置60-80%的內存。更精確一點,在內存容量容許的狀況下面設置比InnoDB tablespaces大10%的內存大小。

innodb_data_file_path:指定表數據和索引存儲的空間,能夠是一個或者多個文件。最後一個數據文件必須是自動擴充的,也只有最後一個文件容許自動擴充。這樣,當空間用完後,自動擴充數據文件就會自動增加(以8MB爲單位)以容納額外的數據。例如: innodb_data_file_path=/disk1/ibdata1:900M;/disk2/ibdata2:50M:autoextend兩個數據文件放在不一樣的磁盤上。數據首先放在ibdata1中,當達到900M之後,數據就放在ibdata2中。一旦達到50MB,ibdata2將以8MB爲單位自動增加。若是磁盤滿了,須要在另外的磁盤上面增長一個數據文件。
innodb_autoextend_increment: 默認是8M, 若是一次insert數據量比較多的話, 能夠適當增長.

innodb_data_home_dir:放置表空間數據的目錄,默認在mysql的數據目錄,設置到和MySQL安裝文件不一樣的分區能夠提升性能。

innodb_log_file_size:該參數決定了recovery speed。太大的話recovery就會比較慢,過小了影響查詢性能,通常取256M能夠兼顧性能和recovery的速度

innodb_log_buffer_size:磁盤速度是很慢的,直接將log寫道磁盤會影響InnoDB的性能,該參數設定了log buffer的大小,通常4M。若是有大的blob操做,能夠適當增大。

innodb_flush_logs_at_trx_commit=2: 該參數設定了事務提交時內存中log信息的處理。
1) =1時,在每一個事務提交時,日誌緩衝被寫到日誌文件,對日誌文件作到磁盤操做的刷新。Truly ACID。速度慢。
2) =2時,在每一個事務提交時,日誌緩衝被寫到文件,但不對日誌文件作到磁盤操做的刷新。只有操做系統崩潰或掉電纔會刪除最後一秒的事務,否則不會丟失事務。
3) =0時, 日誌緩衝每秒一次地被寫到日誌文件,而且對日誌文件作到磁盤操做的刷新。任何mysqld進程的崩潰會刪除崩潰前最後一秒的事務
innodb_file_per_table:能夠存儲每一個InnoDB表和它的索引在它本身的文件中。

transaction-isolation=READ-COMITTED: 若是應用程序能夠運行在READ-COMMITED隔離級別,作此設定會有必定的性能提高。

innodb_flush_method: 設置InnoDB同步IO的方式:
1) Default – 使用fsync()。
2) O_SYNC 以sync模式打開文件,一般比較慢。
3) O_DIRECT,在Linux上使用Direct IO。能夠顯著提升速度,特別是在RAID系統上。避免額外的數據複製和double buffering(mysql buffering 和OS buffering)。
innodb_thread_concurrency: InnoDB kernel最大的線程數。
1) 最少設置爲(num_disks+num_cpus)*2。
2) 能夠經過設置成1000來禁止這個限制

5. 緩存 
緩存有不少種,爲應用程序加上適當的緩存策略會顯著提升應用程序的性能。因爲應用緩存是一個比較大的話題,因此這一部分還須要進一步調研。 

6. Reference 
1) http://www.mysqlperformanceblog.com/
2) Advanced MySQL Performance Optimization, Peter Zaitsev, Tobias Asplund, MySQL Users Conference 2005
3) Improving MySQL Server Performance with Intel C++ Compiler,Peter Zaitsev,Linux World 2005
4) MySQL Performance Optimization, Peter Zaitsev, Percona Ltd, OPEN SOURCE DATABASE CONFERENCE 2006
5) MySQL Server Settings Tuning, Peter Zaitsev, co-founder, Percona Ltd, 2007
6) MySQL Reference Manual

 

 

MySQL性能優化的21個最佳實踐

TechTarget中國原創內容,原文連接:http://www.searchdatabase.com.cn/showcontent_38045.htm

今天,數據庫的操做愈來愈成爲整個應用的性能瓶頸了,這點對於Web應用尤爲明顯。關於數據庫的性能,這並不僅是DBA才須要擔憂的事,而這更是咱們程序員須要去關注的事情。當咱們去設計數據庫表結構,對操做數據庫時(尤爲是查表時的SQL語句),咱們都須要注意數據操做的性能。這裏,咱們不會講過多的SQL語句的優化,而只是針對MySQL這一Web應用最多的數據庫。但願下面的這些優化技巧對你有用。

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

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

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

  

 

  上面兩條SQL語句的差異就是 CURDATE() ,MySQL的查詢緩存對這個函數不起做用。因此,像 NOW() 和 RAND() 或是其它的諸如此類的SQL函數都不會開啓查詢緩存,由於這些函數的返回是會不定的易變的。因此,你所須要的就是用一個變量來代替MySQL的函數,從而開啓緩存。

  2. EXPLAIN 你的 SELECT 查詢

  使用 EXPLAIN 關鍵字可讓你知道MySQL是如何處理你的SQL語句的。這能夠幫你分析你的查詢語句或是表結構的性能瓶頸。

  EXPLAIN 的查詢結果還會告訴你你的索引主鍵被如何利用的,你的數據表是如何被搜索和排序的……等等,等等。

  挑一個你的SELECT語句(推薦挑選那個最複雜的,有多表聯接的),把關鍵字EXPLAIN加到前面。你可使用phpmyadmin來作這個事。而後,你會看到一張表格。下面的這個示例中,咱們忘記加上了group_id索引,而且有表聯接:

  

 

  當咱們爲 group_id 字段加上索引後:

  

 

  咱們能夠看到,前一個結果顯示搜索了 7883 行,然後一個只是搜索了兩個表的 9 和 16 行。查看rows列可讓咱們找到潛在的性能問題。

  3. 當只要一行數據時使用 LIMIT 1

  當你查詢表的有些時候,你已經知道結果只會有一條結果,但由於你可能須要去fetch遊標,或是你也許會去檢查返回的記錄數。

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

  下面的示例,只是爲了找一下是否有「中國」的用戶,很明顯,後面的會比前面的更有效率。(請注意,第一條中是Select *,第二條是Select 1)

  

 

  4. 爲搜索字段建索引

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

  

 

  從上圖你能夠看到那個搜索字串 「last_name LIKE ‘a%’」,一個是建了索引,一個是沒有索引,性能差了4倍左右。

  另外,你應該也須要知道什麼樣的搜索是不能使用正常的索引的。例如,當你須要在一篇大的文章中搜索一個詞時,如: 「WHERE post_content LIKE ‘%apple%’」,索引多是沒有意義的。你可能須要使用MySQL全文索引 或是本身作一個索引(好比說:搜索關鍵詞或是Tag什麼的)

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

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

  並且,這些被用來Join的字段,應該是相同的類型的。例如:若是你要把 DECIMAL 字段和一個 INT 字段Join在一塊兒,MySQL就沒法使用它們的索引。對於那些STRING類型,還須要有相同的字符集才行。(兩個表的字符集有可能不同)

  

 

  6. 千萬不要 ORDER BY RAND()

  想打亂返回的數據行?隨機挑一個數據?真不知道誰發明了這種用法,但不少新手很喜歡這樣用。但你確不瞭解這樣作有多麼可怕的性能問題。

  若是你真的想把返回的數據行打亂了,你有N種方法能夠達到這個目的。這樣使用只讓你的數據庫的性能呈指數級的降低。這裏的問題是:MySQL會不得不去執行RAND()函數(很耗CPU時間),並且這是爲了每一行記錄去記行,而後再對其排序。就算是你用了Limit 1也無濟於事(由於要排序)

  下面的示例是隨機挑一條記錄

  

 

  7. 避免 SELECT *

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

  因此,你應該養成一個須要什麼就取什麼的好的習慣。

  

 

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

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

  就算是你 users 表有一個主鍵叫 「email」的字段,你也別讓它成爲主鍵。使用 VARCHAR 類型來當主鍵會使用得性能降低。另外,在你的程序中,你應該使用表的ID來構造你的數據結構。

  並且,在MySQL數據引擎下,還有一些操做須要使用主鍵,在這些狀況下,主鍵的性能和設置變得很是重要,好比,集羣,分區……

  在這裏,只有一個狀況是例外,那就是「關聯表」的「外鍵」,也就是說,這個表的主鍵,經過若干個別的表的主鍵構成。咱們把這個狀況叫作「外鍵」。好比:有一個「學生表」有學生的ID,有一個「課程表」有課程ID,那麼,「成績表」就是「關聯表」了,其關聯了學生表和課程表,在成績表中,學生ID和課程ID叫「外鍵」其共同組成主鍵。

  9. 使用 ENUM 而不是 VARCHAR

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

  若是你有一個字段,好比「性別」,「國家」,「民族」,「狀態」或「部門」,你知道這些字段的取值是有限並且固定的,那麼,你應該使用 ENUM 而不是 VARCHAR。

  MySQL也有一個「建議」(見第十條)告訴你怎麼去從新組織你的表結構。當你有一個 VARCHAR 字段時,這個建議會告訴你把其改爲 ENUM 類型。使用 PROCEDURE ANALYSE() 你能夠獲得相關的建議。

  10. 從 PROCEDURE ANALYSE() 取得建議

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

  例如,若是你建立了一個 INT 字段做爲你的主鍵,然而並無太多的數據,那麼,PROCEDURE ANALYSE()會建議你把這個字段的類型改爲 MEDIUMINT 。或是你使用了一個 VARCHAR 字段,由於數據很少,你可能會獲得一個讓你把它改爲 ENUM 的建議。這些建議,都是可能由於數據不夠多,因此決策作得就不夠準。

  在phpmyadmin裏,你能夠在查看錶時,點擊 「Propose table structure」 來查看這些建議

  

 

  必定要注意,這些只是建議,只有當你的表裏的數據愈來愈多時,這些建議纔會變得準確。必定要記住,你纔是最終作決定的人。

  11. 儘量的使用 NOT NULL

  除非你有一個很特別的緣由去使用 NULL 值,你應該老是讓你的字段保持 NOT NULL。這看起來好像有點爭議,請往下看。

  首先,問問你本身「Empty」和「NULL」有多大的區別(若是是INT,那就是0和NULL)?若是你以爲它們之間沒有什麼區別,那麼你就不要使用NULL。(你知道嗎?在 Oracle 裏,NULL 和 Empty 的字符串是同樣的!)

  不要覺得 NULL 不須要空間,其須要額外的空間,而且,在你進行比較的時候,你的程序會更復雜。 固然,這裏並非說你就不能使用NULL了,現實狀況是很複雜的,依然會有些狀況下,你須要使用NULL值。


  12. Prepared Statements

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

  Prepared Statements 能夠檢查一些你綁定好的變量,這樣能夠保護你的程序不會受到「SQL注入式」攻擊。固然,你也能夠手動地檢查你的這些變量,然而,手動的檢查容易出問題,並且很常常會被程序員忘了。當咱們使用一些framework或是ORM的時候,這樣的問題會好一些。

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

  雖然最新版本的MySQL在傳輸Prepared Statements是使用二進制形勢,因此這會使得網絡傳輸很是有效率。

  固然,也有一些狀況下,咱們須要避免使用Prepared Statements,由於其不支持查詢緩存。但聽說版本5.1後支持了。

  在PHP中要使用prepared statements,你能夠查看其使用手冊:mysqli 擴展 或是使用數據庫抽象層,如: PDO.

  

 

  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()。

  

 

  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 條件是一個好的方法。下面是一個示例:

  

 

  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

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


TechTarget中國原創內容,原文連接:http://www.searchdatabase.com.cn/showcontent_38045.htm

相關文章
相關標籤/搜索