標籤:
MySQL效能調優與架構設計——第9章 MySQL資料庫Schema設計的效能最佳化
前言:
很多人都認為效能是在通過編寫代碼(程式碼或者是資料庫代碼)的過程中最佳化出來的,其實這是一個非常大的誤區。真正影響效能最大的部分是在設計中就已經產生了的,後期的最佳化很多時候所能夠帶來的改善都只是在解決前妻設計所遺留下來的一些問題而已,而且能夠解決的問題通常也比較有限。本章將就如何在 MySQL 資料庫 Schema 設計的時候保證儘可能的高效,儘可能減少後期的煩惱。
9.1 高效的模型設計
最規範的就一定是最合理的嗎?
在資料庫Schema設計理論方面,一直有一個被大家奉為“葵花寶典”的正常化範式理論。通過範式理論所設計的資料庫Schema邏輯清晰,關係明確,擴充方便,就連儲存的資料量也做到了儘可能的少, 尤其是當範式層級較高的時候,幾乎找不到任何的冗餘資料。在很多人眼裡,資料庫Schema滿足的範式層級越高則該Schema設計的越優秀。 但是,很多人忽略了一點,那就是產生該理論的時期和出發點。關係性資料庫的正常化範式理論誕生於上世紀七十年代初,最根本的目的是讓資料庫中盡量的去除資料的冗餘,保持資料的一致,使資料的修改簡單。
實際上,盡量去除資料的冗餘不僅僅是為了讓我們查詢相同的資料量的時候能夠多返回幾條記錄, 還有一個很重要的原因就是在當時的那個年代,資料的儲存空間是及其昂貴的,而且存放裝置的容量也都非常的小,這一點在硬體存放裝置發展如此迅速的如今,空間大小已經不再是太大的問題了。 而範式理論中的資料一致性和使資料修改簡單保證主要是依靠添在資料庫中添加各種約束來保證,而各種約束對於資料庫來說本身其實就是一個非常消耗資源的事情。 所以,對於基於效能的資料庫Schema設計,我們並不能完全以正常化範式理論來作為唯一的指導。 在設計過程中,應該從實際需求出發,以效能提升為根本目標來展開設計工作,很多時候為了儘可能提高效能,我們必須做反範式設計。
適度冗餘 - 讓Query盡兩減少Join
熟悉MySQL的最佳化器的讀者可能清楚,MySQL的最佳化器雖然號稱使用了新一代的最佳化器技術實現的非常優秀,但是由於目前MySQL所收集的資料統計資訊還不是特別的多,所以起表現並不是特別的讓人滿意,也並非如MySQL官方所宣傳的那樣智能。雖然處理普通Join的時候一般都能比較智能的得到比較高效的執行計畫,但是當遇到一些自查詢或者較為複雜的Join的時候,很容易出現不太合理的執行計畫,不少時候對各表的訪問順序選擇的並不合適,造成複雜Query的整體執行效率低下。 所以,為了讓我們的Query執行計畫儘可能的最佳化,最直接有效方式就是盡量減少Join,而要減少Join,我們就不可避免的需要通過表欄位的冗餘來實現。
這裡我們繼續通過“影響MySQL Server 效能的相關因素” 一章中 “Schema設計對效能的影響” 這一節的一個例子來進一步分析資源消耗的差異。方案一中的group_message表中僅儲存了發布資訊者的ID資訊,而通過冗餘最佳化之後的group_message表中增加了發布資訊者的nick_name資訊存為author。
最佳化前實現列表功能的Query和執行計畫(group_message_bad是最佳化前的表,最佳化後為 group_message表):
[email protected] : example 09:13:41> explain
-> SELECT t.id, t.subject,user.id, user.nick_name
-> FROM (
-> SELECT id, user_id, subject
-> FROM group_message
-> WHERE group_id = 1
-> ORDER BY gmt_modified DESC LIMIT 1,10
-> ) t, user
-> WHERE t.user_id = user.id\G
*************************** 1. row ***************************
id: 1
select_type: PRIMARY
table: <derived2>
type: system
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 1
Extra:
*************************** 2. row ***************************
id: 1
select_type: PRIMARY
table: user
type: const
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: const
rows: 1
Extra:
*************************** 3. row ***************************
id: 2
select_type: DERIVED
table: group_message
type: ALL
possible_keys: group_message_gid_ind
key: group_message_gid_ind
key_len: 4
ref:
rows: 1
Extra: Using filesort
最佳化後實現列表功能的Query和執行計畫:
[email protected] : example 09:14:06> explain
-> SELECT t.id, t.subject, t.user_id, t.author
-> FROM group_message t
-> WHERE group_id = 1
-> ORDER BY gmt_modified DESC LIMIT 1,10\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: t
type: ref
possible_keys: group_message_gid_ind
key: group_message_gid_ind
key_len: 4
ref: const
rows: 1
Extra: Using where; Using filesort
從最佳化前和最佳化後的執行計畫可以看出兩者的差別非常大的,最佳化前必須檢索2個表(group_message和user)才能得到結果,而最佳化後只需要檢索group_message一個表就可以完成,因為 我們將“作者”資訊冗餘到了group_message。
從資料庫範式理論來看,這樣的設計是不合理的。因為可能造成user表和group_message表中的使用者暱稱資料不一致。每次更新使用者暱稱的時候,都需要更新兩個表的資料,為了儘可能讓兩者資料保證一致,應用程式中需要處理更多的邏輯。但是,從效能角度來看的話,這種冗餘是非常有價值的,雖然我們的資料更新邏輯複雜了,但是我們在考慮更新帶來的附加成本的時候,還應該考慮我們到底會有多少更新發生在使用者暱稱上面呢?我們需要考慮的是一個系統的整體效能,而不是系統中單個行為的效能。就像樣本中的暱稱資料,雖然更新的成本增加了,但是查詢的效率提高了,而且發生樣本中查詢的頻率要遠大於更新的頻率,通過少部分操作的成本投入換取更大的效能收穫,實際上是我們系統效能最佳化中經常使用的策略。
在大部分應用系統中,類似於上面樣本中的這種查詢頻繁但是更新較少的資料非常非常多,很多時候如果我們一味的追求範式化理論的Schema設計在高效能要求的系統中是非常不合適的。我個人認為, 資料庫的正常化理論其實質是在概念上的單一化,雖然規範後的資料庫中的表一般都較小,使表中相關列最少。這雖然可能在某些情況下增強了資料庫的可維護性,但在系統要完成一些資料的查詢檢索時, 可能要用複雜的Join才能實現,這勢必會造成查詢檢索的效能低下。如果我們通過拆分Join,通過多次簡單的查詢來在應用中實現Join邏輯,那所帶來的網路開銷將會是非常巨大的。
大欄位垂直分拆 - summary表最佳化
實際上,在上面的樣本中我們同時還用到了另外一種最佳化策略,也就是“大欄位垂直分割”策略。 大欄位垂直分割策略相對於前面介紹的適度冗餘策略在做法上可以說產不多是完全相反的做法。適度冗餘策略是將別的表中的欄位拿過來在自己身上也存一份資料,而大欄位垂直分割簡單來說就是將自己身上的欄位拆分出去放在另外(單獨)的表裡面。 可能很多讀者朋友都會有疑惑了,我們剛剛才分析出了將別的欄位拿過來放自己表裡面為什麼現在又要將自己的欄位分出去呢?這樣不是有些自相矛盾了嗎?
其實並沒有任何矛盾,前面我們將別人的欄位那過來,是因為我們很多時候的查詢需要使用該欄位,為了減少Join帶來的效能消耗才拿過來的。而我們將大欄位拿出去,也是將一些我們在大部分查詢中並不需要使用該欄位的時候才會拿出去。而且,在我們拿出去之前,我們肯定會通過全面的評估比較之後才能做出拆分出去的決定。
那到底什麼樣的欄位適合於從表中拆分出去呢?
首要肯定是大欄位。為什嗎?原因很簡單,就是因為他的大。大欄位一般都是存放著一些較長的Detail資訊,如文章的內容,文章的內容,產品的介紹等等。
其次是和表中其他欄位相比訪問頻率明顯要少很多。由於大欄位存放的內容較多,大部分情況都是占整條記錄的80%以上,而資料庫中資料在資料檔案中的格式一般都是以一條一條記錄為單位來存放。也就是說,如果我們要查詢某些記錄的某幾個欄位,資料庫並不是只需要訪問我們需要查詢的哪幾個欄位,而是需要讀取其他所有欄位(可以在索引中完成整個查詢的情況除外),也無法做到唯讀取我們需要的幾個欄位的資料。這樣,我們就不得不讀取包括大欄位在內的很多並不相干的資料。而由於大欄位所佔的空間比例非常大,自然所浪費的IO資源也就非常之大了。
在這樣的情境下,我們就需要將該大欄位從原表中拆分出來,通過單獨的表進行存放,讓我們在訪問其他資料的時候大大降低IO訪問,從而使效能得到較大的改善。
可能有人會疑惑,雖然移出之後訪問其他欄位的效率提高了,但是當我們需要大欄位的資訊的時候,我們就無法避免的需要通過Join來實現,而使用Join之後的處理效率可能會大打折扣的。其實這個擔心是很合理的,這也就是我們在分拆出大欄位之前需要還需要考慮的第二個因素,訪問頻率的因素了。前面我們就介紹了,決定是否要分拆出,出了“大”之外,還要“頻率低”才行,當然,這裡的“頻率低”只是“相對頻率”而已。而且,這種分拆之後的兩個表的關係都是完全確定的一一對應關係,使用Join在效能方面的影響也並不是特別的大。
那我們在移出大欄位的同時,是否還需要將其他欄位也一併移出呢?其實如果我們已經確定有大欄位需要分拆出主表的時候,對於其他的欄位,只要滿足訪問頻率和大欄位一樣相對於表中其他欄位要低很多的都可以和大欄位同時分拆出來。 實際上,在有些時候,我們甚至都不一定非要大欄位才能進行垂直分拆。在有些情境下,有的表中大部分欄位平時都很少訪問,而其中的某幾個欄位卻是訪問頻率非常高。對於這種表,也非常適合通過垂直分拆來達到最佳化效能的目的。
在“Schema設計對效能的影響”一節中的樣本中,實際上是有兩處用到了“垂直分拆”這個最佳化策略。一處是group_message_bad表中的content大欄位從原表中分拆出來為group_message_content表。 另一處就是將原user_bad表中雖然不大但是平時使用很少的欄位拆分出來新增了user_profile表。
大表水平分拆 - 基於類型的分拆最佳化
“大表水平分割”策略在效能最佳化方面可能被人使用的頻率並不是太多,但是如果使用得當,很可能會給我們帶來不小的驚喜。
我們還是直接通過執行個體來說明問題吧。假設我們將前面樣本中的需求稍微做一下擴充,我們希望group系統總管理員能夠發布系統訊息,而且在每一個group的討論帖的沒一頁都能置頂顯示。
在得到該需求之後,我們的第一反應肯定是通過在group_message表中增加一個識別欄位,用來存放文章的類型,標識出是普通會員的討論貼還是系統管理員的置頂帖。然後在每個列表展示頁面都通過對group_message表的兩次查詢(一次置頂資訊,一次普通討論帖)然後在應用程式中合并再展示。這樣的結果是由於整個group_message表的資料較大,查詢置頂資訊的Query成本會相對有些高。
下面我們換一個思路來考慮一下這個問題:
首先,置頂資訊和其他討論帖完全不會產生任何關聯互動;
其次,置頂資訊的變化相對於其他討論帖來說變化很少;
再次,置頂資訊的訪問頻率非常高;
最後,置頂資訊的量和普通討論帖來比非常之少;
通過上面的這幾個分析,如果我們將置頂資訊單獨存放在普通討論帖之外的其他表裡面,首先不會帶來什麼附加的效能消耗,而且可以使每次檢索置頂資訊的成本都有所下降。由於訪問頻率非常的高, 則因為每次檢索置頂資訊的成本下降而得到較大的節省。數量少而且變化不怎麼頻繁的特點則非常適合使用MySQL 的Query Cache,而如果和普通討論帖在一起由於普通討論帖的頻繁變化帶來group_message 表相關的Query Cache失效問題會讓他無法使用Query Cache功能。
通過上面的分析,我們很容易得出一個更為最佳化的方案來存放這些置頂資訊,那就是新增一張類似於group_message的表來專門存放置頂資訊,我們暫且命名為top_message如下:
由於是全域的,所以省略了group_id資訊,而content資訊,還是同樣可以存放在group_message_content表中。
上面僅僅只是一個樣本,可能在實際應用中並不是如此的簡單,但這裡只是給大家一個思路,讓大家知道如何通過大表的水平分割來對通過最佳化Schema設計提供系統的整體效能。在很多大型的應用中, 由於資料量非常龐大,並發訪問又非常高,到達單台主機都無法支撐單個表的訪問的時候,常常會通過 這種大表的水平分割,存放在多台主機的多個資料庫中實現整體擴充性的提升,這方面的內容我們將在“架構設計”部分的“可擴充設計之資料切分”章節再做更為詳細的介紹。
統計表 - 准即時最佳化
統計表的准即時最佳化策略實際上我們在“影響MySQL Server 效能的相關因素”一章的“商業需求對效能的影響”部分有提出過。簡單來說就是通過定時統計資料來替代即時統計查詢。
為什麼要准即時?
很多人看到這個最佳化策略之後可能都會提出這樣的質疑,為什麼要改變需求將“可以即時”的統計 資訊做成准即時的呢?原因很簡單,因為即時統計的效能消耗成本太高。因為每一次展示(也就是每一 次重新整理頁面)都需要進行統計計算,帶來大量的重複資源浪費。而做成准即時的統計資訊之後,我們每次只需要訪問很小的資料量即可,不需要頻繁的統計計算的工作。
當然,並不是所有的統計資料都適合於通過准即時的統計表最佳化策略來實現的,即使我們希望,產品經理們也不會允許,即使產品經理們也希望那樣,我們的使用者肯定也會不同意。
什麼類型的統計資訊適合通過准即時統計表來最佳化實現?
首先,統計資訊的準確性要求並不是特別的嚴格;
其次,統計資訊對時間並不是太敏感;
再次,統計資訊的訪問非常頻繁,重複執行較多;
最後,參與統計資料量較大;
看看上面的要求,還真不少。不過,大家所維護的系統中確實很可能存在這樣的統計資料展示功能。如系統當前線上人數,論壇系統當前總數、回帖數等,多條件大結果集查詢頁面的總結果數以及總頁數,某些虛擬積分的top n排名等等。
這些統計的計算都會設計到大量的資料,同時也需要大量的計算資源,訪問頻率也都非常的高。如果都通過即時統計,恐怕只要資料量稍微大一些,都會帶來非常大的硬體資源開銷。但在短時間內的不夠精確,又並不會帶來太大使用者體驗的降低。所以完全可以通過定時任務程式,沒隔一定時間段進行一 次統計後存放在專門設計的統計表中。這樣,在統計資料需要展示的時候,我們只需要從統計好的結果資料中取出即可。這樣每次統計資料的展示效能將會成數量級的提升,反而會使整體的使用者體驗上升。
9.2 合適的資料類型
實際上在很多資料庫的設計最佳化文檔中都有關於通過最佳化資料類型的最佳化說明內容,在 MySQL中, 我們同樣也可以通過資料類型的最佳化達到最佳化整個Schema設計的目的。
最佳化資料類型提高效能的主要原理在於以下幾個方面:
1. 通過選用更“小”的資料類型減少儲存空間,使查詢相同資料需要的IO資源降低;
2. 通過合適的資料類型加速資料的比較;
下面我們還是通過分析一些常用資料類型的資料存放區格式和長度來看看哪些資料類型可以在最佳化中利用上吧。
數字日期類型
我們先來看看存放長度基本固定的一些資料類型的儲存長度和取值範圍。
對於數字類型,這裡分別列出了整數類型和小數類型,也就是浮點數類型。實際上,還有一類通過二進位格式以字串來存放的數字類型如DECIMAL(DEC)[(M[,D])],NUMERIC[(M[,D])],由於其存放長度主要通過其定義時候的的M所決定,M定義為多大,則實際存放就有多長。M代表整個位元長度,而D則表示小數點後的位元,預設M為10,D為0。一般來說,主要用在固定精度的場合,由於其存放長度較大,而且考慮到這種資料完全可以變化形式以整數存放,所以筆者個人並不是精選。
對於數位儲存,一般使用到浮點型資料的場合也不應該太多。主要出於兩個原因,一個是浮點型資料本身實際上是一個並不精確的數字,只是一個近似值,另一個原因就是完全可以通過乘以一個固定的係數轉換為整型資料來存放。這樣不僅可以解決資料不精確的問題,同時也讓資料的處理更為高效。
時間儲存格式總類並不是太多,我們常用的主要就是DATETIME,DATE和TIMESTAMP這三種了。從儲存空間來看TIMESTAMP最少,四個位元組,而其他兩種資料類型都是八個位元組,多了一倍。而TIMESTAMP的缺點在於他只能儲存從1970年之後的時間,而另外兩種時間類型可以存放最早從1001年開始的時間。如果有需要存放早於1970年之前的時間的需求,我們必須放棄TIMESTAMP類型,但是只要我們不需要使用1970年之前的時間,最好盡量使用TIMESTAMP來減少儲存空間的佔用。
上面所列出的主要是一些存放固定長度,且我們平時可能常用到的一些類型。通過這個對照表格,我們可以很直觀的看出哪種類型佔用的儲存空間大,哪種佔用的空間小。這樣,在資料類型選擇的時候,我們就可以結合各種類型的儲存範圍以及業務中可能存在的資料作出對應,然後選擇儲存空間最先的類型來使用。
字元儲存類型
我們再來看看存放字元的資料類型。
CHAR[(M)]類型屬於靜態長度類型,存放長度完全以字元數來計算,所以最終的儲存長度是基於字元集的,如latin1則最大儲存長度為255位元組,但是如果使用gbk則最大儲存長度為510位元組。CHAR類型的儲存特點是不管我們實際存放多長資料,在資料庫中都會存放M個字元,不夠的通過空格補上,M預設為1。雖然CHAR會通過空格補齊存放的空間,但是在訪問資料的時候,MySQL會忽略最後的所有空格,所以如果我們的實際資料中如果在最後確實需要空格,則不能使用CHAR類型來存放。在MySQL5.0.3之前的版本中,如果我們定義CHAR的時候M值超過255,MySQL會自動將CHAR類型進行轉換為可以存入對應資料量的 TEXT 類型,如 CHAR(1000)會自動轉換為 TEXT,CHAR(10000)則會轉為 MEDIUMTEXT。而從MySQL5.0.3開始,所有超過255的定義MySQL都會直接拒絕並給出錯誤資訊,不再自動轉換。
VARCHAR[(M)]屬於動態儲存裝置長度類型,僅存佔用實際儲存資料的長度。其存放的最大長度與MySQL版本有關,在5.0.3之前的版本VARCHAR以字元數控制最儲存的最大長度,最大隻能存放255個字元,佔用儲存空間的實際大小與字元集有關。但是從5.0.3開始,VARCHAR的最大儲存限制已經更改為位元組數限制了,擴充到可以存放65535 bytes的資料,不同的字元集可能存放的字元數並不一樣。也就是說,在MySQL5.0.3之前的版本,M所代表的是字元數,而從5.0.3版本開始,M的代表意思已經是位元組數了。
VARCHAR的儲存特點是不管我們設定M為多大的值,真正佔用的儲存空間都只有我們所存入的實際資料的大小,和CHAR不同的是VARCHAR會保留我們存入資料最後的空格,也就是說我們存入是什麼樣,MySQL返回給我們的也會是什麼樣。在VARCHAR類型欄位的資料中,MySQL會在每個VARCHAR資料中使用1個或 者2個位元組用來存放VARCHAR資料的實際長度,當我們的實際資料在255位元組之內的時候,會使用1位元組來存放實際長度,而大於255位元組的時候,則需要使用2位元組來存放。
TINYTEXT,TEXT,MEDIUMTEXT和LONGTEXT這四種類型同屬於一種儲存方式,都是動態儲存裝置長度類型,不同的僅僅是最大長度的限制。四種類型的定義都是通過最大字元數來限制,但是他們的字元數限制實際上是可以理解為位元組數限制的,因為當我們使用多位元組字元集的時候,實際能存放的字元書並沒最大字元數那麼多,而是以單位元組字元來計算的字元數。此外,由於是動態儲存裝置長度類型,所以和VARCHAR一樣,每個欄位資料之前都需要一個存放實際長度的空間。TINYTEXT需要1個位元組來存放,TEXT需要2個位元組,MEDIUMTEXT和LONGTEXT則分別需要3個和4個位元組來存放實際資料長度。實際上,除了MySQL 內嵌的最大長度限制之外,他們還受到用戶端與伺服器端的網路通訊緩衝區最大值 (max_allowed_packet)的限制。
這四種TEXT類型和CHAR及VARCHAR在實際使用中存在幾個不一樣的地方:
◆ 不能設定預設值;
◆ 只有TEXT可以使用TEXT[(M)]這樣的方式通過M設定大小;
◆ 基於這四種類型的索引必須指定前置長度;
其他常用類型
除了上面這些欄位類型之外會被我們經常使用到之外,我們還會使用到的資料類型主要有以下這些。
對於BIT類型,M表示每個值的bits數目,預設為1,最大為64 bits。對於MySQL來說這是一個新的類型,因為從MySQL5.0.3才開始真正實現(在之前實際上是TINYINT(1)),而且僅僅支援MyISAM 儲存引擎,但是從MySQL5.0.5開始Memory,Innodb和NDB Cluster儲存引擎也開始“支援”了。在 MyISAM中,BIT的儲存空間很小,是真正的實現了通過bit來儲存,但是在其他的一些儲存引擎中就不一 樣了,因為他們是轉換為最小的INT類型儲存的,所以佔用的空間也沒有節省,還不如直接使用INT類的資料類型存放來得直觀。
對於SET和ENUM類型,主要內容基本處於較少變化狀態且值比較少的欄位。雖然這兩個欄位所佔用的儲存空間都較少,但是由於在使用方面較其他的資料類型要略為複雜一些,所以在實際環境中一般使用還是較少。
誰都知道,資料量(這裡主要指資料記錄條數)的增加肯定會讓資料庫的檢索查詢效率降低。所以很多時候人們大都希望通過減少資料庫中關鍵表的記錄條數來獲得資料庫效能的提升。實際上,除了這種通過控制資料記錄條數來控制資料總量的辦法之外,我們還可以通過選擇更小的資料類型來讓資料庫通過更小的空間存放相同的資料量,這對於檢索同樣的資料所帶來的IO消耗自然會降低,效能也就很自然得到了提升。
此外,由於CPU對不同資料的處理方式不一樣,就會造成不同類型的資料在各種運算處理如比較,排序等方面的處理效率存在差異。所以,對於我們需要經常進行比較計算以及排序等消耗 CPU資源的欄位,應該盡量選擇處理更為迅速的欄位類型。如通過整數類型代替浮點數或者字元類型。
9.3 規範的對象命名
規範的命名本身並不會對效能有任何影響,在這裡單獨列出一節來講,主要是因為這是一個不太被人重視,但是對後期的資料庫維護影響非常大的內容。就像程式設計語言各自的一些不成文編碼基本規範一樣,雖然在最初使用的時候並看不錯太多的利益,反而會被人認為是一種束縛,但是當每一個人在接手維護一段編寫很不規範的代碼的時候,我估計大部分人都會非常鬱悶,甚至在心裡暗罵當初的編寫者。
其實任何系統都一樣,沒有任何規範可循,完全一個天馬行空的作風,只會給後人(甚至可能是自己) 留下一個讓人摸不著頭腦的爛攤子,難以維護。
對於資料庫物件的命名規範其實可以很簡單,而且業界也並不存在一個嚴格的統一規定,只需要在一個公司內足夠統一基本就可以了。
一般來說,我個人建議需要注意以下一些方面:
1、資料庫和表名應儘可能和所服務的業務模組名一致;
這樣,在 DBA 維護相關資料庫物件的時候,新開發人員程式開發過程中,相關技術(或非技術)人員整理商務邏輯和資料關係的時候,都能夠非常容易理解其中的關係。
2、服務於同一子模組的一類表盡量以子模組名(或部分單詞)為首碼或尾碼;
對同類功能的表增加首碼或者尾碼,也是讓查看使用該表的各類人員能夠很快的根據相關對象的名稱就聯想到相應的功能,以及相關業務。不論是從維護角度,還是從使用角度來看都會帶來非常大的便利性。
3、表名應盡量包含與所存放資料相對應的單詞;
這對於新員工來說尤其重要,要想儘快的熟悉資料,儘快瞭解相關業務,快速的定位元據庫中各表對應的資料意義是非常有協助的。
4、欄位名稱也盡量保持和實際資料相對應
這一點的意義我想各位讀者朋友應該都非常的清楚,每個表都會有很多的欄位對應資料的各種不同屬性,要搞清楚各自代表的含義,除了完整規範的說明文檔之外,命名清晰合理的欄位名也是一個有用的補充,而且更為直接。
5、索引名稱盡量包含所有的索引鍵欄位名或者縮寫,且各欄位名在索引名中的順序應與索引鍵在索引中的索引順序一致,且盡量包含一個類似於 idx 或者 ind 之類的首碼或者尾碼,以表名其物件類型是索引,同時還可以包含該索引所屬表的名稱; 這樣做最大的好處在於 DBA 在維護過程中能夠非常直接清晰的通過索引名稱就瞭解到該索引大部分的資訊。
6、約束等其他對象也應該儘可能包含所屬表或其他對象的名稱,以表名各自關係。
上面列出的只是一個比較初略的規範建議,各位讀者朋友完全可以根據各自公司的習慣,制定自己的命名規範,只要適用,就可以了。規範不在多,而在實用。而且一旦制定的規範,就必須嚴格的按照規範執行,否則就變成了個花架子沒有任何實際的意義了。
9.4 小結
通過這一章的內容,希望能夠讓大家明白一個道理,“資料庫系統的效能不是最佳化出來的,更多的是設計出來的”。資料庫 Schema 的設計並不如很多人想象的那樣只是一個簡單的對象對應實現,而是一個系統工程。要想設計出一個既效能高效又足夠滿足業務需求,既邏輯清晰又關係簡單的資料庫Schema 結構,不僅僅需要足夠的資料庫系統知識,還需要足夠瞭解應用系統的商務邏輯。
摘自:《MySQL效能調優與架構設計》簡朝陽
轉載請註明出處:
JesseLZJ
出處:http://jesselzj.cnblogs.com
MySQL效能調優與架構設計——第9章 MySQL資料庫Schema設計的效能最佳化