10條關於數據庫的技巧和經驗
1)字段長度和類型:數據來自外系統的一定要與外系統保持一致,避免插入失敗或截斷。禁止使用Blob,Clob,Text,Image等大字段。
2)中間表:多對多關聯需要添加中間表,多對一加關聯字段即可。關聯字段為了避免數據遷移麻煩,可以不用自增長ID關聯,而是用實際業務關聯的值。
3)聯接查詢:若表字段過多,則根據業務拆出一個或多個字表。若有關聯過多,則可在主表冗余一些需要的字段來減少查詢時的表關聯。
4)索引與性能:(後續)
5)並發訪問(讀寫):當讀操作遠大於寫操作時,利用中間件分發或在程序中自行配置不同的讀和寫數據源來實現讀寫分離。主庫的數據修改同步到各個從庫上去。以MySQL為例,從庫可使用MyISAM引擎提升性能,主從分離後不僅服務器增加,同時還極大緩解排它鎖和共享鎖的競爭。
6)並發訪問(寫):
四種並發問題
丟失或覆蓋更新:多個事務讀取同一數據,並發更新時發生更新丟失問題。
髒讀:一個事務讀取到了另一個未提交事務寫的數據。
不可重復讀:一個事務重新讀取前面讀過的數據,發現已被另一事務修改。
幻影讀:一個事務重新讀取前面讀過的數據,發現多了或少了幾行。
Oracle和SQLServer默認級別為讀提交(Read-Committed, RC),MySQL/InnoDB默認為可重復讀(Read-Repeatable, RR)。能解決的並發問題如下:
========================================================================
隔離級別 髒讀(Dirty Read) 不可重復讀(NonRepeatable Read) 幻讀(Phantom Read)
========================================================================
未提交讀(Read uncommitted) 可能 可能 可能
已提交讀(Read committed) 不可能 可能 可能
可重復讀(Repeatable read) 不可能 不可能 可能
可串行化(Serializable ) 不可能 不可能 不可能
串行化事務
最簡單策略就是修改事務級別為可串行化,這樣某一事務執行時會禁止其他事務執行。但這種方法實際上不可行,因為它使程序對數據庫的操作變成單線程的了,不能充分共享數據庫資源。
悲觀鎖控制
當用戶執行的操作時會在數據上加鎖,直到當前事務釋放鎖時,其他事務才能執行與該鎖相沖突的操作。
以MySQL的事務為例:
set autocommit=0;
begin;
select status from t_goods where id=1
for update
...
commit;
默認為行鎖,超過一定行數升級為表鎖。執行select... for update後,則其他select...for update對此數據的查詢會阻塞,但普通select此表不會受影響。
樂觀鎖控制
用時間戳或版本號控制。用戶讀數據時不鎖定,但查詢數據時也一起將控制字段查出。當用戶更新時先檢查此時數據庫中控制字段的值與程序中之前拿到的值是否相同。不同則此條數據已被處理,相同則更新數據,並同時更新控制字段的值為當前時間戳或版本號加1。
7)小事務:避免長時間鎖定數據,可以將大數據量的更新或刪除分成批次,一個批次是一個小事務。通過記錄已成功批次的序號方便意外終止後的恢復。
8)數據刪除:刪除時可先邏輯刪除,更新一個標記列的值表示數據已無效,達到記錄留存的作用。日後真正無用時可做物理刪除。
9)擴展性:核心表預留出Int,Long,Char等各種類型的擴展字段。
10)分區分庫:日均數據增長量大的表,可以按進行分區甚至復合分區。過期數據進行刪除或歸檔到歷史庫。歸檔方法可采用:定期請求DBA手動、應用程序(如Java)中實現、服務器上部署Shell腳本實現等。