總結一下自己的一點見解
1.1首先需要了解數據庫查找的過程
磁盤是一個扁平的圓盤(與電唱機的唱片類似)。盤面上有許多稱為磁道的圓圈,數據就記錄在這些磁道上。磁盤可以是單片的,也可以是由若干盤片組成的盤組棘伴,每一盤片上有兩個面。如下圖中所示的6片盤組為例屁置,除去最頂端和最底端的外側面不存儲數據之外焊夸,一共有10個面可以用來保存信息。
當磁盤驅動器執(zhí)行讀/寫功能時蓝角。盤片裝在一個主軸上阱穗,并繞主軸高速旋轉,當磁道在讀/寫頭(又叫磁頭) 下通過時使鹅,就可以進行數據的讀 / 寫了揪阶。
一般磁盤分為固定頭盤(磁頭固定)和活動頭盤。固定頭盤的每一個磁道上都有獨立的磁頭患朱,它是固定不動的鲁僚,專門負責這一磁道上數據的讀/寫。
活動頭盤 (如上圖)的磁頭是可移動的。每一個盤面上只有一個磁頭(磁頭是雙向的冰沙,因此正反盤面都能讀寫)侨艾。它可以從該面的一個磁道移動到另一個磁道。所有磁頭都裝在同一個動臂上拓挥,因此不同盤面上的所有磁頭都是同時移動的(行動整齊劃一)唠梨。當盤片繞主軸旋轉的時候,磁頭與旋轉的盤片形成一個圓柱體侥啤。各個盤面上半徑相同的磁道組成了一個圓柱面当叭,我們稱為柱面 。因此盖灸,柱面的個數也就是盤面上的磁道數蚁鳖。
1.2磁盤的讀/寫原理和效率
磁盤上數據必須用一個三維地址唯一標示:柱面號、盤面號赁炎、塊號(磁道上的盤塊)醉箕。
讀/寫磁盤上某一指定數據需要下面3個步驟:
(1) 首先移動臂根據柱面號使磁頭移動到所需要的柱面上,這一過程被稱為定位或查找 甘邀。
(2) 如上圖11.3中所示的6盤組示意圖中琅攘,所有磁頭都定位到了10個盤面的10條磁道上(磁頭都是雙向的)垮庐。這時根據盤面號來確定指定盤面上的磁道松邪。
(3) 盤面確定以后,盤片開始旋轉哨查,將指定塊號的磁道段移動至磁頭下逗抑。
經過上面三個步驟,指定數據的存儲位置就被找到寒亥。這時就可以開始讀/寫操作了邮府。
訪問某一具體信息,由3部分時間組成:
● 查找時間(seek time) Ts: 完成上述步驟(1)所需要的時間溉奕。這部分時間代價最高褂傀,最大可達到0.1s左右。
● 等待時間(latency time) Tl: 完成上述步驟(3)所需要的時間加勤。由于盤片繞主軸旋轉速度很快仙辟,一般為7200轉/分(電腦硬盤的性能指標之一, 家用的普通硬盤的轉速一般有5400rpm(筆記本)、7200rpm幾種)鳄梅。因此一般旋轉一圈大約0.0083s叠国。
● 傳輸時間(transmission time) Tt: 數據通過系統(tǒng)總線傳送到內存的時間,一般傳輸一個字節(jié)(byte)大概0.02us=210^(-8)s
磁盤讀取數據是以盤塊(block)為基本單位的戴尸。位于同一盤塊中的所有數據都能被一次性全部讀取出來粟焊。而磁盤IO代價主要花費在查找時間Ts上。因此我們應該盡量將相關信息存放在同一盤塊,同一磁道中项棠”ǎ或者至少放在同一柱面或相鄰柱面上,以求在讀/寫信息時盡量減少磁頭來回移動的次數沾乘,避免過多的查找時間Ts*怜奖。
1.3
sql語句和其他語言沒有多大的區(qū)別,需要經過解析器和編譯器來轉換成二進制代碼翅阵。在sql中還有優(yōu)化性能的緩存等組件歪玲。
block數據由DMA從硬盤copy到內存中
2.1
mysql優(yōu)化可以朝著上面描述等幾個方面去著手。
● 對于查找時間的優(yōu)化掷匠,sql聚集索引使用b-樹來減小查找時間
由上圖可以明白滥崩,查找到對應盤塊記錄的次數為樹的高度,這也是它比二叉樹所在對優(yōu)勢讹语,底的增大使得樹的高度減小钙皮,從而減小查詢次數。在此基礎上顽决,發(fā)展出了B+樹短条,b*樹更加增加了數據的查找的性能。
●對與聚集索引才菠,因為其為在空間中連續(xù)的存儲茸时,所以最好不要進行大量的修改和增刪操作。
b+樹在表單數據量非常龐大時會退化成遍歷查詢赋访,所以在表單數據量變得很大的時候我們需要對表進行分區(qū)操作可都,具體操作請看(http://www.cnblogs.com/AK2012/archive/2012/12/25/2012-1228.html)
●對于sql非聚集索引,采用的是另外一種為r樹的數據結構蚓耽。
下圖是Guttman論文中的一幅圖:
這里簡單解釋一下渠牲,對于空間中不規(guī)則的r8,用最小的矩形來把它包裹住步悠,而r9,r10也是相同的道理签杈。r8,r9,r10的頁節(jié)點為r3,為葉子節(jié)點的最小包裹矩形鼎兽,依次類推答姥。
r樹很好的解決了不連貫的空間存儲如何查找的問題,但是擴展到6維以上會導致r樹性能下降退化為遍歷操作(我不是很明白這點)
非聚集索引使用指針來表達對應的區(qū)塊接奈,使得修改操作變得容易很多踢涌。
3.優(yōu)化
3.1
對于sql語句編譯和解析器來說,
select ** from dual *
SELECT * FROM dual
為不同的語句序宦,這樣在編譯的時候會增加編譯的時間睁壁,所以在寫sql語句的時候盡聊使用規(guī)范化的語句,保證一致性。
**select * from orderheader where changetime >'2010-10-20 00:00:01'
**select * from orderheader where changetime >'2010-09-22 00:00:01'
以上兩句語句潘明,查詢優(yōu)化器認為是不同的SQL語句行剂,需要解析兩次。如果采用綁定變量
select * from orderheader where changetime >@chgtime
3.2
有的時候會需要進行一些模糊查詢比如
select*from contact where username like ‘%yue%’
關鍵詞%yue%钳降,由于yue前面用到了“%”厚宰,索引這時候實效sql引擎便會遍歷全表,除非必要遂填,否則不要在關鍵詞前加%铲觉。盡量使用yue%等確定的前綴
3.3
綁定變量在php和java對數據庫操作的時候很常見,我在查找python對次此采取的操作時并沒有查到對應的方法吓坚。
先給sql引擎發(fā)送一個sql語句撵幽,后面使用綁定變量,引擎中語句緩存會識別語句從而減少解析和編譯的時間礁击。
我看到一篇blog中寫的批量執(zhí)行語句時已經對綁定變量做了優(yōu)化的盐杂。(MySQLdb中的cursor.executemany我懷疑并沒有做對應的優(yōu)化策略)
3.4盡量少使用or語句,在執(zhí)行or語句的時候哆窿,sql引擎會放棄索引查找的方式而使用遍歷查找链烈,極大的增加了查詢的時間。
3.5
使用temp表單來減少對主表對查詢操作,減輕主表熱點程度挚躯。大大減少了程序執(zhí)行中“共享鎖”阻塞“更新鎖”强衡,減少了阻塞,提高了并發(fā)性能秧均。
3.6
SQL Server中一句SQL語句默認就是一個事務食侮,在該語句執(zhí)行完成后也是默認commit的号涯。其實目胡,這就是begin tran的一個最小化的形式,好比在每句語句開頭隱含了一個begin tran链快,結束時隱含了一個commit誉己。
有些情況下,我們需要顯式聲明begin tran域蜗,比如做“插巨双、刪、改”操作需要同時修改幾個表霉祸,要求要么幾個表都修改成功筑累,要么都不成功。begin tran 可以起到這樣的作用丝蹭,它可以把若干SQL語句套在一起執(zhí)行慢宗,最后再一起commit。好處是保證了數據的一致性,但任何事情都不是完美無缺的镜沽。Begin tran付出的代價是在提交之前敏晤,所有SQL語句鎖住的資源都不能釋放,直到commit掉缅茉。
可見嘴脾,如果Begin tran套住的SQL語句太多,那數據庫的性能就糟糕了蔬墩。在該大事務提交之前译打,必然會阻塞別的語句,造成block很多拇颅。
Begin tran使用的原則是扶平,在保證數據一致性的前提下,begin tran 套住的SQL語句越少越好蔬蕊!有些情況下可以采用觸發(fā)器同步數據结澄,不一定要用begin tran。
3.7
SQL Server 表連接的三種方式(參考鏈接地址:http://www.cnblogs.com/ATree/archive/2011/02/13/sql_optimize_1.html)
(1) Merge Join
(2) Nested Loop Join
(3) Hash Join
SQL Server 2000只有一種join方式——Nested Loop Join岸夯,如果A結果集較小麻献,那就默認作為外表,A中每條記錄都要去B中掃描一遍猜扮,實際掃過的行數相當于A結果集行數x B結果集行數勉吻。所以如果兩個結果集都很大,那Join的結果很糟糕旅赢。
SQL Server 2005新增了Merge Join齿桃,如果A表和B表的連接字段正好是聚集索引所在字段,那么表的順序已經排好煮盼,只要兩邊拼上去就行了短纵,這種join的開銷相當于A表的結果集行數加上B表的結果集行數,一個是加,一個是乘,可見merge join 的效果要比Nested Loop Join好多了闪水。
如果連接的字段上沒有索引,那SQL2000的效率是相當低的悠就,而SQL2005提供了Hash join,相當于臨時給A充易,B表的結果集加上索引梗脾,因此SQL2005的效率比SQL2000有很大提高,我認為盹靴,這是一個重要的原因炸茧。
總結一下帆疟,在表連接時要注意以下幾點:
(1) 連接字段盡量選擇聚集索引所在的字段
(2) 仔細考慮where條件,盡量減小A宇立、B表的結果集
4
在物理層面上
●增加磁盤的轉速(比較難以實現)
●橫向擴展和縱向擴展(由于硬件設備價格的持續(xù)下降踪宠,很多都會采用這樣的方式)
使用橫向擴展,用負載均衡設備(h5)或者是計算機(使用負載均衡軟件Ngix等)對大量sql語句請求做分流可以大大減輕單個設備的壓力妈嘹。
縱向擴展不太了解柳琢,先暫時放一放(==)
●讀寫分離策略
實際上大量的sql請求為讀請求,在一臺master機器上執(zhí)行update/insert操作润脸,而在多臺slave機器上執(zhí)行讀請求也可以降低設備壓力柬脸。master把更后的表單再 copy給slave。