(轉自網絡)php
現在隨着互聯網的發展,數據的量級也是撐指數的增加,從GB到TB到PB。對數據的各類操做也是越發的困難,傳統的關係性數據庫已經沒法知足快速查詢與插入數據的需求。這個時候NoSQL的出現暫時解決了這一危機。它經過下降數據的安全性,減小對事務的支持,減小對複雜查詢的支持,來獲取性能上的提高。可是,在有些場合NoSQL一些折衷是沒法知足使用場景的,就好比有些使用場景是絕對要有事務與安全指標的。這個時候NoSQL確定是沒法知足的,因此仍是須要使用關係性數據庫。html
雖然關係型數據庫在海量數據中遜色於NoSQL數據庫,可是若是你操做正確,它的性能仍是會知足你的需求的。針對數據的不一樣操做,其優化方向也是不盡相同。對於數據移植,查詢和插入等操做,能夠從不一樣的方向去考慮。而在優化的時候還須要考慮其餘相關操做是否會產生影響。就好比你能夠經過建立索引提升查詢性能,可是這會致使插入數據的時候由於要創建更新索引致使插入性能下降,你是否能夠接受這一下降那。因此,對數據庫的優化是要考慮多個方向,尋找一個折衷的最佳方案。mysql
最簡單也是最經常使用的優化就是查詢。由於對於CRUD操做,read操做是佔據了絕大部分的比例,因此read的性能基本上決定了應用的性能。對於查詢性能最經常使用的就是建立索引。通過測試,2000萬條記錄,每條記錄200字節兩列varchar類型的。當不使用索引的時候查詢一條記錄須要一分鐘,而當建立了索引的時候查詢時間能夠忽略。可是,當你在已有數據上添加索引的時候,則須要耗費很是大的時間。我插入2000萬條記錄以後,再建立索引大約話費了幾十分鐘的樣子。程序員
建立索引的弊端和場合。雖然建立索引能夠很大程度上優化查詢的速度,可是弊端也是很明顯的。一個是在插入數據的時候,建立索引也須要消耗部分的時間,這就使得插入性能在必定程度上下降;另外一個很明顯的是數據文件變的更大。在列上建立索引的時候,每條索引的長度是和你建立列的時候制定的長度相同的。好比你建立varchar(100),當你在該列上建立索引,那麼索引的長度則是102字節,由於長度超過64字節則會額外增長2字節記錄索引的長度。sql
從上圖能夠看到我在YCSB_KEY這一列(長度100)上建立了一個名字爲index_ycsb_key的索引,每條索引長度都爲102,想象一下當數據變的巨大無比的時候,索引的大小也是不能夠小覷的。並且從這也能夠看出,索引的長度和列類型的長度還不一樣,好比varchar它是變長的字符類型(請看MySQL數據類型分析),實際存儲長度是是實際字符的大小,可是索引倒是你聲明的長度的大小。你建立列的時候聲明100字節,那麼索引長度就是這個字節再加上2,它無論你實際存儲是多大。shell
除了建立索引須要消耗時間,索引文件體積會變的愈來愈大以外,建立索引也須要看的你存儲數據的特徵。當你存儲數據很大一部分都是重複記錄,那這個時候建立索引是百害而無一利。請先查看MySQL索引介紹。因此,當不少數據重複的時候,索引帶來的查詢提高的效果是能夠直接忽略的,可是這個時候你還要承受插入數據的時候建立索引帶來的性能消耗。數據庫
在MySQL中有多種多樣的緩存,有的緩存負責緩存查詢語句,也有的負責緩存查詢數據。這些緩存內容客戶端沒法操做,是由server端來維護的。它會隨着你查詢與修改等相應不一樣操做進行不斷更新。經過其配置文件咱們能夠看到在MySQL中的緩存:緩存
在這裏主要分析query cache,它是主要用來緩存查詢數據。當你想使用該cache,必須把query_cache_size大小設置爲非0。當設置大小爲非0的時候,server會就會緩存每次查詢返回的結果,到下次相同查詢server就直接從緩存獲取數據,而不是再執行查詢。能緩存的數據量就和你的size大小設置有關,因此當你設置的足夠大,數據能夠徹底緩存到內存,速度就會很是之快。安全
可是,query cache也有它的弊端。當你對數據表作任何的更新操做(update/insert/delete)等操做,server爲了保證緩存與數據庫的一致性,會強制刷新緩存數據,致使緩存數據所有失效。因此,當一個表格的更新數據表操做很是多的話,query cache是不會起到查詢提高的性能,還會影響其餘操做的性能。服務器
其實對於查詢性能提高,最重要也是最根本的手段也是slow_query的設置。
當你設置slow_query_log爲on的時候,server端會對每次的查詢進行記錄,當超過你設置的慢查詢時間 (long_query_time)的時候就把該條查詢記錄到日誌。而你對性能進行優化的時候,就能夠分析慢查詢日誌,對慢查詢的查詢語句進行有目的的優化。能夠經過建立各類索引,能夠經過分表等操做。那爲何要分庫分表那,當不分庫分表的時候那個地方是限制性能的地方啊。下面咱們就簡單介紹。
分庫分表應該算是查詢優化的殺手鐗了。上述各類措施在數據量達到必定等級以後,能起到優化的做用已經不明顯了。這個時候就必須對數據量進行分流。分流通常有分庫與分表兩種措施。而分表又有垂直切分與水平切分兩種方式。下面咱們就針對每一種方式簡單介紹。
對於mysql,其數據文件是以文件形式存儲在磁盤上的。當一個數據文件過大的時候,操做系統對大文件的操做就會比較麻煩與耗時,並且有的操做系統就不支持大文件,因此這個時候就必須分表了。另外對於mysql經常使用的存儲引擎是Innodb,它的底層數據結構是B+樹。當其數據文件過大的時候,B+樹就會從層次和節點上比較多,當查詢一個節點的時候可能會查詢不少層次,而這一定會致使屢次IO操做進行裝載進內存,確定會耗時的。除此以外還有Innodb對於B+樹的鎖機制。對每一個節點進行加鎖,那麼當更改表結構的時候,這時候就會樹進行加鎖,當表文件大的時候,這能夠認爲是不可實現的。
因此綜上咱們就必須進行分表與分庫的操做。
當數據量達到必定等級以後,那麼移庫將是一個很是慎重又危險的工做。在移庫中保證先後數據的一致性,各類突發狀況的處理,移庫過程當中數據的變遷,每個都是一個很是困難的問題。
一、對查詢進行優化、應儘可能避免全表掃描、首先應考慮在 where 及 order by 涉及的列上創建索引。
30、儘可能避免向客戶端返回大數據量、若數據量過大、應該考慮相應需求是否合理。
大多數的MySQL服務器都開啓了查詢緩存。這是提升性最有效的方法之一,並且這是被MySQL的數據庫引擎處理的。當有不少相同的查詢被執行了多 次的時候,這些查詢結果會被放到一個緩存中,這樣,後續的相同的查詢就不用操做表而直接訪問緩存結果了。
這裏最主要的問題是,對於程序員來講,這個事情是很容易被忽略的。由於,咱們某些查詢語句會讓MySQL不使用緩存。請看下面的示例:
1
2
3
4
5
6
|
// 查詢緩存不開啓
$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'" );
|
上面兩條SQL語句的差異就是 CURDATE() ,MySQL的查詢緩存對這個函數不起做用。因此,像 NOW() 和 RAND() 或是其它的諸如此類的SQL函數都不會開啓查詢緩存,由於這些函數的返回是會不定的易變的。因此,你所須要的就是用一個變量來代替MySQL的函數,從而 開啓緩存。
使用 EXPLAIN 關鍵字可讓你知道MySQL是如何處理你的SQL語句的。這能夠幫你分析你的查詢語句或是表結構的性能瓶頸。
EXPLAIN 的查詢結果還會告訴你你的索引主鍵被如何利用的,你的數據表是如何被搜索和排序的……等等,等等。
挑一個你的SELECT語句(推薦挑選那個最複雜的,有多表聯接的),把關鍵字EXPLAIN加到前面。你能夠使用phpmyadmin來作這個 事。而後,你會看到一張表格。下面的這個示例中,咱們忘記加上了group_id索引,而且有表聯接:
當咱們爲 group_id 字段加上索引後:
咱們能夠看到,前一個結果顯示搜索了 7883 行,然後一個只是搜索了兩個表的 9 和 16 行。查看rows列可讓咱們找到潛在的性能問題。
當你查詢表的有些時候,你已經知道結果只會有一條結果,但由於你可能須要去fetch遊標,或是你也許會去檢查返回的記錄數。
在這種狀況下,加上 LIMIT 1 能夠增長性能。這樣同樣,MySQL數據庫引擎會在找到一條數據後中止搜索,而不是繼續日後查少下一條符合記錄的數據。
下面的示例,只是爲了找一下是否有「中國」的用戶,很明顯,後面的會比前面的更有效率。(請注意,第一條中是Select *,第二條是Select 1)
// 沒有效率的: $r = mysql_query( "SELECT * FROM user WHERE country = 'China'" ); if (mysql_num_rows( $r ) > 0) { // ... } // 有效率的: $r = mysql_query( "SELECT 1 FROM user WHERE country = 'China' LIMIT 1" ); if (mysql_num_rows( $r ) > 0) { // ... }4. 爲搜索字段建索引
索引並不必定就是給主鍵或是惟一的字段。若是在你的表中,有某個字段你總要會常常用來作搜索,那麼,請爲其創建索引吧。
從上圖你能夠看到那個搜索字串 「last_name LIKE ‘a%’」,一個是建了索引,一個是沒有索引,性能差了4倍左右。
另外,你應該也須要知道什麼樣的搜索是不能使用正常的索引的。例如,當你須要在一篇大的文章中搜索一個詞時,如: 「WHERE post_content LIKE ‘%apple%’」,索引多是沒有意義的。你可能須要使用MySQL 全文索引 或是本身作一個索引(好比說:搜索關鍵詞或是Tag什麼的)
若是你的應用程序有不少 JOIN 查詢,你應該確認兩個表中Join的字段是被建過索引的。這樣,MySQL內部會啓動爲你優化Join的SQL語句的機制。
並且,這些被用來Join的字段,應該是相同的類型的。例如:若是你要把 DECIMAL 字段和一個 INT 字段Join在一塊兒,MySQL就沒法使用它們的索引。對於那些STRING類型,還須要有相同的字符集才行。(兩個表的字符集有可能不同)
1
2
3
4
5
6
|
// 在state中查找company
$r = mysql_query("SELECT company_name FROM users
LEFT JOIN companies ON (users.state = companies.state)
WHERE users.id = $user_id ");
// 兩個 state 字段應該是被建過索引的,並且應該是至關的類型,相同的字符集。
|
想打亂返回的數據行?隨機挑一個數據?真不知道誰發明了這種用法,但不少新手很喜歡這樣用。但你確不瞭解這樣作有多麼可怕的性能問題。
若是你真的想把返回的數據行打亂了,你有N種方法能夠達到這個目的。這樣使用只讓你的數據庫的性能呈指數級的降低。這裏的問題是:MySQL會不得 不去執行RAND()函數(很耗CPU時間),並且這是爲了每一行記錄去記行,而後再對其排序。就算是你用了Limit 1也無濟於事(由於要排序)
下面的示例是隨機挑一條記錄
1
2
3
4
5
6
7
8
9
|
// 千萬不要這樣作:
$r = mysql_query( "SELECT username FROM user ORDER BY RAND() LIMIT 1" );
// 這要會更好:
$r = mysql_query( "SELECT count(*) FROM user" );
$d = mysql_fetch_row( $r );
$rand = mt_rand(0, $d [0] - 1);
$r = mysql_query( "SELECT username FROM user LIMIT $rand, 1" );
|
從數據庫裏讀出越多的數據,那麼查詢就會變得越慢。而且,若是你的數據庫服務器和WEB服務器是兩臺獨立的服務器的話,這還會增長網絡傳輸的負載。
因此,你應該養成一個須要什麼就取什麼的好的習慣。
1
2
3
4
5
6
7
8
9
|
// 不推薦
$r = mysql_query( "SELECT * FROM user WHERE user_id = 1" );
$d = mysql_fetch_assoc( $r );
echo "Welcome {$d['username']}" ;
// 推薦
$r = mysql_query( "SELECT username FROM user WHERE user_id = 1" );
$d = mysql_fetch_assoc( $r );
echo "Welcome {$d['username']}" ;
|
咱們應該爲數據庫裏的每張表都設置一個ID作爲其主鍵,並且最好的是一個INT型的(推薦使用UNSIGNED),並設置上自動增長的 AUTO_INCREMENT標誌。
就算是你 users 表有一個主鍵叫 「email」的字段,你也別讓它成爲主鍵。使用 VARCHAR 類型來當主鍵會使用得性能降低。另外,在你的程序中,你應該使用表的ID來構造你的數據結構。
並且,在MySQL數據引擎下,還有一些操做須要使用主鍵,在這些狀況下,主鍵的性能和設置變得很是重要,好比,集羣,分區……
在這裏,只有一個狀況是例外,那就是「關聯表」的「外鍵」,也就是說,這個表的主鍵,經過若干個別的表的主鍵構成。咱們把這個狀況叫作「外鍵」。比 如:有一個「學生表」有學生的ID,有一個「課程表」有課程ID,那麼,「成績表」就是「關聯表」了,其關聯了學生表和課程表,在成績表中,學生ID和課 程ID叫「外鍵」其共同組成主鍵。
ENUM 類型是很是快和緊湊的。在實際上,其保存的是 TINYINT,但其外表上顯示爲字符串。這樣一來,用這個字段來作一些選項列表變得至關的完美。
若是你有一個字段,好比「性別」,「國家」,「民族」,「狀態」或「部門」,你知道這些字段的取值是有限並且固定的,那麼,你應該使用 ENUM 而不是 VARCHAR。
MySQL也有一個「建議」(見第十條)告訴你怎麼去從新組織你的表結構。當你有一個 VARCHAR 字段時,這個建議會告訴你把其改爲 ENUM 類型。使用 PROCEDURE ANALYSE() 你能夠獲得相關的建議。
PROCEDURE ANALYSE() 會讓 MySQL 幫你去分析你的字段和其實際的數據,並會給你一些有用的建議。只有表中有實際的數據,這些建議纔會變得有用,由於要作一些大的決定是須要有數據做爲基礎 的。
例如,若是你建立了一個 INT 字段做爲你的主鍵,然而並無太多的數據,那麼,PROCEDURE ANALYSE()會建議你把這個字段的類型改爲 MEDIUMINT 。或是你使用了一個 VARCHAR 字段,由於數據很少,你可能會獲得一個讓你把它改爲 ENUM 的建議。這些建議,都是可能由於數據不夠多,因此決策作得就不夠準。
在phpmyadmin裏,你能夠在查看錶時,點擊 「Propose table structure」 來查看這些建議
必定要注意,這些只是建議,只有當你的表裏的數據愈來愈多時,這些建議纔會變得準確。必定要記住,你纔是最終作決定的人。
除非你有一個很特別的緣由去使用 NULL 值,你應該老是讓你的字段保持 NOT NULL。這看起來好像有點爭議,請往下看。
首先,問問你本身「Empty」和「NULL」有多大的區別(若是是INT,那就是0和NULL)?若是你以爲它們之間沒有什麼區別,那麼你就不要 使用NULL。(你知道嗎?在 Oracle 裏,NULL 和 Empty 的字符串是同樣的!)
不要覺得 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.」
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 .
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
// 建立 prepared statement
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();
}
|
正常的狀況下,當你在當你在你的腳本中執行一個SQL語句的時候,你的程序會停在那裏直到沒這個SQL語句返回,而後你的程序再往下繼續執行。你可 以使用無緩衝查詢來改變這個行爲。
關於這個事情,在PHP的文檔中有一個很是不錯的說明: mysql_unbuffered_query() 函數:
「mysql_unbuffered_query() sends the SQL query query to MySQL without automatically fetching and buffering the result rows as mysql_query() does. This saves a considerable amount of memory with SQL queries that produce large result sets, and you can start working on the result set immediately after the first row has been retrieved as you don’t have to wait until the complete SQL query has been performed.」
上面那句話翻譯過來是說,mysql_unbuffered_query() 發送一個SQL語句到MySQL而並不像mysql_query()同樣去自動fethch和緩存結果。這會至關節約不少可觀的內存,尤爲是那些會產生大 量結果的查詢語句,而且,你不須要等到全部的結果都返回,只須要第一行數據返回的時候,你就能夠開始立刻開始工做於查詢結果了。
然而,這會有一些限制。由於你要麼把全部行都讀走,或是你要在進行下一次的查詢前調用 mysql_free_result()清除結果。並且, mysql_num_rows() 或 mysql_data_seek() 將沒法使用。因此,是否使用無緩衝的查詢你須要仔細考慮。
不少程序員都會建立一個 VARCHAR(15) 字段來存放字符串形式的IP而不是整形的IP。若是你用整形來存放,只須要4個字節,而且你能夠有定長的字段。並且,這會爲你帶來查詢上的優點,尤爲是當 你須要使用這樣的WHERE條件:IP between ip1 and ip2。
咱們必須要使用UNSIGNED INT,由於 IP地址會使用整個32位的無符號整形。
而你的查詢,你能夠使用 INET_ATON() 來把一個字符串IP轉成一個整形,並使用 INET_NTOA() 把一個整形轉成一個字符串IP。在PHP中,也有這樣的函數 ip2long() 和 long2ip() 。
1
|
$r = "UPDATE users SET ip = INET_ATON('{$_SERVER['REMOTE_ADDR']}') WHERE user_id = $user_id" ;
|
若是表中的全部字段都是「固定長度」的,整個表會被認爲是 「static」 或 「fixed-length」 。 例如,表中沒有以下類型的字段: VARCHAR,TEXT,BLOB。只要你包括了其中一個這些字段,那麼這個表就不是「固定長度靜態表」了,這樣,MySQL 引擎會用另外一種方法來處理。
固定長度的表會提升性能,由於MySQL搜尋得會更快一些,由於這些固定的長度是很容易計算下一個數據的偏移量的,因此讀取的天然也會很快。而若是 字段不是定長的,那麼,每一次要找下一條的話,須要程序找到主鍵。
而且,固定長度的表也更容易被緩存和重建。不過,惟一的反作用是,固定長度的字段會浪費一些空間,由於定長的字段不管你用不用,他都是要分配那麼多 的空間。
使用「垂直分割」技術(見下一條),你能夠分割你的表成爲兩個一個是定長的,一個則是不定長的。
「垂直分割」是一種把數據庫中的表按列變成幾張表的方法,這樣能夠下降表的複雜度和字段的數目,從而達到優化的目的。(之前,在銀行作過項目,見過 一張表有100多個字段,很恐怖)
示例一 :在Users表中有一個字段是家庭地址,這個字段是可選字段,相比起,並且你在數據庫操做的時候除了個 人信息外,你並不須要常常讀取或是改寫這個字段。那麼,爲何不把他放到另一張表中呢? 這樣會讓你的表有更好的性能,你們想一想是否是,大量的時候,我對於用戶表來講,只有用戶ID,用戶名,口令,用戶角色等會被常用。小一點的表老是會有 好的性能。
示例二 : 你有一個叫 「last_login」 的字段,它會在每次用戶登陸時被更新。可是,每次更新時會致使該表的查詢緩存被清空。因此,你能夠把這個字段放到另外一個表中,這樣就不會影響你對用戶 ID,用戶名,用戶角色的不停地讀取了,由於查詢緩存會幫你增長不少性能。
另外,你須要注意的是,這些被分出去的字段所造成的表,你不會常常性地去Join他們,否則的話,這樣的性能會比不分割時還要差,並且,會是極數級 的降低。
若是你須要在一個在線的網站上去執行一個大的 DELETE 或 INSERT 查詢,你須要很是當心,要避免你的操做讓你的整個網站中止相應。由於這兩個操做是會鎖表的,表一鎖住了,別的操做都進不來了。
Apache 會有不少的子進程或線程。因此,其工做起來至關有效率,而咱們的服務器也不但願有太多的子進程,線程和數據庫連接,這是極大的佔服務器資源的事情,尤爲是 內存。
若是你把你的表鎖上一段時間,好比30秒鐘,那麼對於一個有很高訪問量的站點來講,這30秒所積累的訪問進程/線程,數據庫連接,打開的文件數,可 能不只僅會讓你泊WEB服務Crash,還可能會讓你的整臺服務器立刻掛了。
因此,若是你有一個大的處理,你定你必定把其拆分,使用 LIMIT 條件是一個好的方法。下面是一個示例:
1
2
3
4
5
6
7
8
9
10
|
while (1) {
//每次只作1000條
mysql_query( "DELETE FROM logs WHERE log_date <= '2009-11-01' LIMIT 1000" );
if (mysql_affected_rows() == 0) {
// 沒得可刪了,退出!
break ;
}
// 每次都要休息一下子
usleep(50000);
}
|
對於大多數的數據庫引擎來講,硬盤操做多是最重大的瓶頸。因此,把你的數據變得緊湊會對這種狀況很是有幫助,由於這減小了對硬盤的訪問。
參看 MySQL 的文檔 Storage Requirements 查看全部的數據類型。
若是一個表只會有幾列罷了(好比說字典表,配置表),那麼,咱們就沒有理由使用 INT 來作主鍵,使用 MEDIUMINT, SMALLINT 或是更小的 TINYINT 會更經濟一些。若是你不須要記錄時間,使用 DATE 要比 DATETIME 好得多。
固然,你也須要留夠足夠的擴展空間,否則,你往後來幹這個事,你會死的很難看,參看Slashdot 的例子 (2009年11月06日),一個簡單的ALTER TABLE語句花了3個多小時,由於裏面有一千六百萬條數據。
在 MySQL 中有兩個存儲引擎 MyISAM 和 InnoDB,每一個引擎都有利有弊。酷殼之前文章《MySQL: InnoDB 仍是 MyISAM? 》討論和這個事情。
MyISAM 適合於一些須要大量查詢的應用,但其對於有大量寫操做並非很好。甚至你只是須要update一個字段,整個表都會被鎖起來,而別的進程,就算是讀進程都 沒法操做直到讀操做完成。另外,MyISAM 對於 SELECT COUNT(*) 這類的計算是超快無比的。
InnoDB 的趨勢會是一個很是複雜的存儲引擎,對於一些小的應用,它會比 MyISAM 還慢。他是它支持「行鎖」 ,因而在寫操做比較多的時候,會更優秀。而且,他還支持更多的高級應用,好比:事務。
下面是MySQL的手冊
使用 ORM (Object Relational Mapper),你可以得到可靠的性能增漲。一個ORM能夠作的全部事情,也能被手動的編寫出來。可是,這須要一個高級專家。
ORM 的最重要的是「Lazy Loading」,也就是說,只有在須要的去取值的時候纔會去真正的去作。但你也須要當心這種機制的反作用,由於這頗有可能會由於要去建立不少不少小的查 詢反而會下降性能。
ORM 還能夠把你的SQL語句打包成一個事務,這會比單獨執行他們快得多得多。
目前,我的最喜歡的PHP的ORM是:Doctrine 。
「永久連接」的目的是用來減小從新建立MySQL連接的次數。當一個連接被建立了,它會永遠處在鏈接的狀態,就算是數據庫操做已經結束了。並且,自 從咱們的Apache開始重用它的子進程後——也就是說,下一次的HTTP請求會重用Apache的子進程,並重用相同的 MySQL 連接。
在理論上來講,這聽起來很是的不錯。可是從我的經驗(也是大多數人的)上來講,這個功能製造出來的麻煩事更多。由於,你只有有限的連接數,內存問 題,文件句柄數,等等。
並且,Apache 運行在極端並行的環境中,會建立不少不少的了進程。這就是爲何這種「永久連接」的機制工做地很差的緣由。在你決定要使用「永久連接」以前,你須要好好地 考慮一下你的整個系統的架構。