而你的每一次
mysql
-h${HOSTNAME}
-P${PORT}
-u${USERNAME}...
都是一個新的連接(SESSION)AUTOCOMMIT=0
這個僅是對當前SESSION的變數進行了設置,並沒有改變所有的MYSQL事務設置。
㈡ mysql的事務四個特性以及事務的四個隔離級別
分別是原子性、一致性、隔離性、持久性。
原子性是指事務包含的所有操作要麼全部成功,要麼全部失敗回滾,因此事務的操作如果成功就必須要完全應用到資料庫,如果操作失敗則不能對資料庫有任何影響。
一致性是指事務必須使資料庫從一個一致性狀態變換到另一個一致性狀態,也就是說一個事務執行之前和執行之後都必須處於一致性狀態。舉例來說,假設用戶A和用戶B兩者的錢加起來一共是1000,那麼不管A和B之間如何轉賬、轉幾次賬,事務結束後兩個用戶的錢相加起來應該還得是1000,這就是事務的一致性。
隔離性是當多個用戶並發訪問資料庫時,比如同時操作同一張表時,資料庫為每一個用戶開啟的事務,不能被其他事務的操作所干擾,多個並發事務之間要相互隔離。關於事務的隔離性資料庫提供了多種隔離級別,稍後會介紹到。
持久性是指一個事務一旦被提交了,那麼對資料庫中的數據的改變就是永久性的,即便是在資料庫系統遇到故障的情況下也不會丟失提交事務的操作。例如我們在使用JDBC操作資料庫時,在提交事務方法後,提示用戶事務操作完成,當我們程序執行完成直到看到提示後,就可以認定事務已經正確提交,即使這時候資料庫出現了問題,也必須要將我們的事務完全執行完成。否則的話就會造成我們雖然看到提示事務處理完畢,但是資料庫因為故障而沒有執行事務的重大錯誤。這是不允許的。
在資料庫操作中,在並發的情況下可能出現如下問題:
正是為了解決以上情況,資料庫提供了幾種隔離級別。
資料庫事務的隔離級別有4個,由低到高依次為Read uncommitted(未授權讀取、讀未提交)、Read committed(授權讀取、讀提交)、Repeatable read(可重復讀取)、Serializable(序列化),這四個級別可以逐個解決臟讀、不可重復讀、幻象讀這幾類問題。
雖然資料庫的隔離級別可以解決大多數問題,但是靈活度較差,為此又提出了悲觀鎖和樂觀鎖的概念。
悲觀鎖,它指的是對數據被外界(包括本系統當前的其他事務,以及來自外部系統的事務處理)修改持保守態度。因此,在整個數據處理過程中,將數據處於鎖定狀態。悲觀鎖的實現,往往依靠資料庫提供的鎖機制。也只有資料庫層提供的鎖機制才能真正保證數據訪問的排他性,否則,即使在本系統的數據訪問層中實現了加鎖機制,也無法保證外部系統不會修改數據。
商品t_items表中有一個欄位status,status為1代表商品未被下單,status為2代表商品已經被下單(此時該商品無法再次下單),那麼我們對某個商品下單時必須確保該商品status為1。假設商品的id為1。
如果不採用鎖,那麼操作方法如下:
但是上面這種場景在高並發訪問的情況下很可能會出現問題。例如當第一步操作中,查詢出來的商品status為1。但是當我們執行第三步Update操作的時候,有可能出現其他人先一步對商品下單把t_items中的status修改為2了,但是我們並不知道數據已經被修改了,這樣就可能造成同一個商品被下單2次,使得數據不一致。所以說這種方式是不安全的。
在上面的場景中,商品信息從查詢出來到修改,中間有一個處理訂單的過程,使用悲觀鎖的原理就是,當我們在查詢出t_items信息後就把當前的數據鎖定,直到我們修改完畢後再解鎖。那麼在這個過程中,因為t_items被鎖定了,就不會出現有第三者來對其進行修改了。需要注意的是,要使用悲觀鎖,我們必須關閉mysql資料庫的自動提交屬性,因為MySQL默認使用autocommit模式,也就是說,當你執行一個更新操作後,MySQL會立刻將結果進行提交。我們可以使用命令設置MySQL為非autocommit模式: set autocommit=0;
設置完autocommit後,我們就可以執行我們的正常業務了。具體如下:
上面的begin/commit為事務的開始和結束,因為在前一步我們關閉了mysql的autocommit,所以需要手動控制事務的提交。
上面的第一步我們執行了一次查詢操作: select status from t_items where id=1 for update; 與普通查詢不一樣的是,我們使用了 select…for update 的方式,這樣就通過資料庫實現了悲觀鎖。此時在t_items表中,id為1的那條數據就被我們鎖定了,其它的事務必須等本次事務提交之後才能執行。這樣我們可以保證當前的數據不會被其它事務修改。需要注意的是,在事務中,只有 SELECT ... FOR UPDATE 或 LOCK IN SHARE MODE 操作同一個數據時才會等待其它事務結束後才執行,一般 SELECT ... 則不受此影響。拿上面的實例來說,當我執行 select status from t_items where id=1 for update; 後。我在另外的事務中如果再次執行 select status from t_items where id=1 for update; 則第二個事務會一直等待第一個事務的提交,此時第二個查詢處於阻塞的狀態,但是如果我是在第二個事務中執行 select status from t_items where id=1; 則能正常查詢出數據,不會受第一個事務的影響。
使用 select…for update 會把數據給鎖住,不過我們需要注意一些鎖的級別,MySQL InnoDB默認Row-Level Lock,所以只有「明確」地指定主鍵或者索引,MySQL 才會執行Row lock (只鎖住被選取的數據) ,否則MySQL 將會執行Table Lock (將整個數據表單給鎖住)。舉例如下:
1、 select * from t_items where id=1 for update;
這條語句明確指定主鍵(id=1),並且有此數據(id=1的數據存在),則採用row lock。只鎖定當前這條數據。
2、 select * from t_items where id=3 for update;
這條語句明確指定主鍵,但是卻查無此數據,此時不會產生lock(沒有元數據,又去lock誰呢?)。
3、 select * from t_items where name='手機' for update;
這條語句沒有指定數據的主鍵,那麼此時產生table lock,即在當前事務提交前整張數據表的所有欄位將無法被查詢。
4、 select * from t_items where id>0 for update; 或者 select * from t_items where id>1 for update; (註:>在SQL中表示不等於)
上述兩條語句的主鍵都不明確,也會產生table lock。
5、 select * from t_items where status=1 for update; (假設為status欄位添加了索引)
這條語句明確指定了索引,並且有此數據,則產生row lock。
6、 select * from t_items where status=3 for update; (假設為status欄位添加了索引)
這條語句明確指定索引,但是根據索引查無此數據,也就不會產生lock。
樂觀鎖( Optimistic Locking ) 相對悲觀鎖而言,樂觀鎖假設認為數據一般情況下不會造成沖突,所以只會在數據進行提交更新的時候,才會正式對數據的沖突與否進行檢測,如果發現沖突了,則返回用戶錯誤的信息,讓用戶決定如何去做。實現樂觀鎖一般來說有以下2種方式:
㈢ mysql資料庫 事務提交怎麼處理
查看 MySQL 客戶端的事務提交方式命令:select @@autocommit;
修改 MySQL 客戶端的事務提交方式為手動提交命令:set @@autocommit = 0;
(註:0 表示手動提交,即使用 MySQL 客戶端執行 SQL 命令後必須使用commit命令執行事務,否則所執行的 SQL 命令無效,如果想撤銷事務則使用 rollback 命令。1 表示自動提交,即在 MySQL 客戶端不在需要手動執行 commit 命令。)
MySQL 在自動提交模式下,每個 SQL 語句都是一個獨立的事務。
注意:
1、手動設置set @@autocommit = 0,即設定為非自動提交模式,只對當前的mysql命令行窗口有效,打開一個新的窗口後,默認還是自動提交;
2、對於非自動提交模式,比如在命令行中添加一條記錄,退出命令行後在重新打開命令行,之前插入的記錄是不在的。(用select * from + 表名 驗證一下就可以了)
㈣ mysql的特點是什麼
一、MySQL資料庫的特點和優勢:
(1)功能強大
MySQL 中提供了多種資料庫存儲引擎,各引擎各有所長,適用於不同的應用場合,用戶可以選擇最合適的引擎以得到最高性能,可以處理每天訪問量超過數億的高強度的搜索 Web 站點。MySQL5 支持事務、視圖、存儲過程、觸發器等。
(2)支持跨平台
MySQL 支持至少 20 種以上的開發平台,包括 Linux、Windows、FreeBSD 、IBMAIX、AIX、FreeBSD 等。這使得在任何平台下編寫的程序都可以進行移植,而不需要對程序做任何的修改。
(3)運行速度快
高速是 MySQL 的顯著特性。在 MySQL 中,使用了極快的 B 樹磁碟表(MyISAM)和索引壓縮;通過使用優化的單掃描多連接,能夠極快地實現連接;SQL 函數使用高度優化的類庫實現,運行速度極快。
(4)支持面向對象
PHP 支持混合編程方式。編程方式可分為純粹面向對象、純粹面向過程、面句對象與面向過程混合 3 種方式。
(5)安全性高
靈活和安全的許可權與密碼系統,允許基本主機的驗證。連接到伺服器時,所有的密碼傳輸均採用加密形式,從而保證了密碼的安全。
(6)成本低
MySQL 資料庫開放源代碼且無版權制約,是一種完全免費的產品,用戶可以直接通過網路下載,自主性及使用成本低。體積小,安裝方便。歷史悠久,用戶使用活躍,遇到問題可以尋求幫助,易於維護。
(7)支持各種開發語言
MySQL 為各種流行的程序設計語言提供支持,為它們提供了很多的 API 函數,包括 PHP、ASP.NET、Java、Eiffel、Python、Ruby、Tcl、C、C++、Perl 語言等。
(8)資料庫存儲容量大
MySQL 資料庫的最大有效表尺寸通常是由操作系統對文件大小的限制決定的,而不是由 MySQL 內部限制決定的。InnoDB 存儲引擎將 InnoDB 表保存在一個表空間內,該表空間可由數個文件創建,表空間的最大容量為 64TB,可以輕松處理擁有上千萬條記錄的大型資料庫。
(9)支持強大的內置函數
PHP 中提供了大量內置函數,幾乎涵蓋了 Web 應用開發中的所有功能。它內置了資料庫連接、文件上傳等功能,MySQL 支持大量的擴展庫,如 MySQLi 等,可以為快速開發 Web 應用提供便利。
二、相比其他資料庫的特點和優勢:
(1) 對事務的提交
MySQL默認是自動提交,不需要在寫commit指令或者點擊commit按鈕。
(2) 分頁查詢
MySQL是直接在SQL語句中寫"select... from ...where...limit m, n",有limit就可以實現分頁。PHP里還可以用SEEK定位到結果集的位置。
(3) 事務隔離級別
MySQL是read commited的隔離級別。
一個session讀取數據時,其他session不能更改數據,但可以在表最後插入數據。session更新數據時,要加上排它鎖,其他session無法訪問數據。
(4) 復制簡單
MySQL復制伺服器配置簡單。
(5) 自動增長的數據類型處理
MYSQL有自動增長的數據類型,插入記錄時不用操作此欄位,會自動獲得數據值。
(6)單引號的處理
MYSQL里可以用雙引號包起字元串。
(7) 日期欄位的處理
MYSQL日期欄位分DATE和TIME兩種。
(8)空字元的處理
MYSQL的非空欄位也有空的內容,NULL或空字元。
㈤ 安裝MySQL事務資料庫都需要哪些步驟
按常規的方法進行安裝
安裝MySQL完成後,啟動MySQL(和PHP搭配之最佳組合)binWinMySQL(和PHP搭配之最佳組合)admin
再退出
運行
MySQL(和PHP搭配之最佳組合)binmydqld-nt--remove
MySQL(和PHP搭配之最佳組合)binMySQL(和PHP搭配之最佳組合)d-max-nt--install
以上二行是去掉不支持事務處理的MySQL(和PHP搭配之最佳組合)服務,改成支持MySQL(和PHP搭配之最佳組合)事務處理的服務
然後在c:下建一個ibdata目錄及iblogs目錄,當然名字可以不一樣,記住這二個名字及盤符,以後要用到,你也可以不建在C盤,然後,打開c:winnt或c:windows目錄下的my.ini,在最後添加:以下內容為程序代碼:
1.innodb_data_file_path=ibdata1:2000M;ibdata2:2000M
2.innodb_data_home_dir=c:ibdata
3.set-variable=innodb_mirrored_log_groups=1
4.innodb_log_group_home_dir=c:iblogs
5.set-variable=innodb_log_files_in_group=3
6.set-variable=innodb_log_file_size=30M
7.set-variable=innodb_log_buffer_size=8M
8.innodb_flush_log_at_trx_commit=1
9.innodb_log_arch_dir=c:iblogs
10.innodb_log_archive=0
11.set-variable=innodb_buffer_pool_size=80M
12.set-variable=innodb_additional_mem_pool_size=10M
13.set-variable=innodb_file_io_threads=4
14.set-variable=innodb_lock_wait_timeout=50
其中
1.innodb_data_file_path=ibdata1:2000M;ibdata2:2000M 這一行中的2000M可以自己改成200m,看你盤的容量大小,MySQL(和PHP搭配之最佳組合)推薦10G及以上的硬碟空間最好用這樣的設置;
以下這一行
1.innodb_data_home_dir=c:ibdata 也可以改成你自己起的目錄,主要是看你自己在剛才建的目錄在哪裡啦
按照以上的方法,你已經安裝MySQL好了MySQL(和PHP搭配之最佳組合)的事務資料庫,不過你要是按照MySQL(和PHP搭配之最佳組合)手冊上的方法安裝,把上面的一段配製放到my.cnf是去的話,可是會出錯哦
好了,現在讓我們試試看是不是安裝完成了,啟動apache(Unix平台最流行的WEB伺服器平台),或iis,在服務里啟動MySQL(和PHP搭配之最佳組合)的服務,打開phpmyadmin,輸入:SHOWvariableslikehave_%
你要是看到下面的結果,那說明你安裝MySQL成功了
以下內容為程序代碼
1.Variable_nameValue
2.have_bdbYES
3.have_innodbYES
4.have_isamYES
5.have_raidNO
6.have_symlinkYES
7.have_opensslNO
8.have_query_cacheYES
9. 註:MySQL(和PHP搭配之最佳組合)的事務處理方法的使用同其它資料庫語法相似,在這里我就不多說了,另外,MySQL(和PHP搭配之最佳組合)將在4.3中實現外鍵及子查詢,簡單的外鍵已經在4.0中都已經實現了,只是不怎麼方便,相信以後會做得更好些。
㈥ 談談你對 mysql 事務的認識 我是php初學者不懂這個 想請教大神教我
先簡單介紹一下事務吧!事務是DBMS得執行單位。它由有限得資料庫操作序列組成得。但不是任意得資料庫操作序列都能成為事務。一般來說,事務是必須滿足4個條件(ACID)
原子性(Autmic):事務在執行性,要做到「要麼不做,要麼全做!」,就是說不允許事務部分得執行。即使因為故障而使事務不能完成,在rollback時也要消除對資料庫得影響!
一致性(Consistency):事務得操作應該使使資料庫從一個一致狀態轉變倒另一個一致得狀態!就拿網上購物來說吧,你只有即讓商品出庫,又讓商品進入顧客得購物籃才能構成事務!
隔離性(Isolation):如果多個事務並發執行,應象各個事務獨立執行一樣!
持久性(Durability):一個成功執行得事務對資料庫得作用是持久得,即使資料庫應故障出錯,也應該能夠恢復!
MYSQL的事務處理主要有兩種方法。
1、用begin,rollback,commit來實現
begin
開始一個事務
rollback 事務回滾
commit 事務確認
2、直接用set來改變mysql的自動提交模式
MYSQL默認是自動提交的,也就是你提交一個QUERY,它就直接執行!我們可以通過
set autocommit=0
禁止自動提交
set autocommit=1 開啟自動提交
來實現事務的處理。
但注意當你用 set
autocommit=0
的時候,你以後所有的SQL都將做為事務處理,直到你用commit確認或rollback結束,注意當你結束這個事務的同時也開啟了個新的事務!按第一種方法只將當前的作為一個事務!
個人推薦使用第一種方法!
MYSQL中只有INNODB和BDB類型的數據表才能支持事務處理!其他的類型是不支持的!(切記!)
下次有空說下MYSQL的數據表的鎖定和解鎖!
MYSQL5.0 WINXP下測試通過~ ^_^
mysql> use test;
Database
changed
mysql> CREATE TABLE `dbtest`(
-> id int(4)
-> ) TYPE=INNODB;
Query OK, 0 rows affected, 1 warning (0.05
sec)
mysql> select * from dbtest
-> ;
Empty set (0.01
sec)
mysql> begin;
Query OK, 0 rows affected (0.00
sec)
mysql> insert into dbtest value(5);
Query OK, 1 row affected
(0.00 sec)
mysql> insert into dbtest value(6);
Query OK, 1 row
affected (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.00
sec)
mysql> select * from dbtest;
+------+
| id
|
+------+
| 5 |
| 6 |
+------+
2 rows in set (0.00
sec)
mysql> begin;
Query OK, 0 rows affected (0.00
sec)
mysql> insert into dbtest values(7);
Query OK, 1 row affected
(0.00 sec)
mysql> rollback;
Query OK, 0 rows affected (0.00
sec)
mysql> select * from dbtest;
+------+
| id
|
+------+
| 5 |
| 6 |
+------+
2 rows in set (0.00
sec)
mysql>
*******************************************************************************************************************
[PHP]
function
Tran( $sql ) {
$judge = 1;
mysql_query('begin');
foreach ($sql as $v) {
if
( !mysql_query($v) ) {
$judge =
0;
}
}
if ($judge == 0)
{
mysql_query('rollback');
return
false;
}
elseif ($judge == 1) {
mysql_query('commit');
return true;
}
}
[/PHP]
************************************************
<?php
$handler=mysql_connect("localhost","root","");
mysql_select_db("task");
mysql_query("SET
AUTOCOMMIT=0");//設置為不自動提交,因為MYSQL默認立即執行
mysql_query("BEGIN");//開始事務定義
if(!mysql_query("insert
into trans (id)
values('2')"))
{
mysql_query("ROOLBACK");//判斷當執行失敗時回滾
}
if(!mysql_query("insert
into trans (id)
values('4')"))
{
mysql_query("ROOLBACK");//判斷執行失敗回滾
}
mysql_query("COMMIT");//執行事務
mysql_close($handler);
?>
引自:http://www.cnblogs.com/in-loading/archive/2012/02/21/2361702.html
㈦ mysql怎麼給操作兩個資料庫的sql加事務
mysql一般表使用innodb引擎才能使用事務,請先確定表引擎為innodb
㈧ mysql proxy是否支持事務,是否支持跨庫
MySQL Proxy 支持事務,讀寫分離就會把這個作為切分轉發依據之一;
也支持跨庫,但是不曉得你是否問的事務跨庫?這個就不清楚了、誰知道請補充。
參考:
http://dev.mysql.com/doc/refman/5.6/en/mysql-proxy-using.html
http://dev.mysql.com/doc/refman/5.6/en/mysql-proxy-faq.html
㈨ Mysql資料庫中,事務是指什麼如何使用該功能
什麼是事務? x0dx0ax0dx0a事務是邏輯上的一組操作,組成這組操作的各個單元,要不全都成功要不全都失敗,這個特性就是事務 x0dx0ax0dx0a注意:mysql數據支持事務,但是要求必須是innoDB存儲引擎 x0dx0ax0dx0a解決這個問題: x0dx0ax0dx0amysql的事務解決這個問題,因為mysql的事務特性,要求這組操作,要不全都成功,要不全都失敗,這樣就避免了某個操作成功某個操作失敗。利於數據的安全 x0dx0ax0dx0a如何使用: x0dx0ax0dx0a(1)在執行sql語句之前,我們要開啟事務 start transaction; x0dx0ax0dx0a(2)正常執行我們的sql語句 x0dx0ax0dx0a(3)當sql語句執行完畢,存在兩種情況: x0dx0ax0dx0a1,全都成功,我們要將sql語句對資料庫造成的影響提交到資料庫中,committ x0dx0ax0dx0a2,某些sql語句失敗,我們執行rollback(回滾),將對資料庫操作趕緊撤銷 x0dx0ax0dx0a(注意:mysql數據支持事務,但是要求必須是innoDB存儲引擎) x0dx0amysql> create table bank(name varchar(20),money decimal(5,1))engine=innodb defau x0dx0alt charset=utf8; x0dx0ax0dx0amysql> inset into bank values('shaotuo',1000),('laohu',5000); x0dx0ax0dx0amysql> select*from bank; x0dx0a+---------+--------+ x0dx0a| name | money | x0dx0a+---------+--------+ x0dx0a| shaotuo | 1000.0 | x0dx0a| laohu | 5000.0 | x0dx0a+---------+--------+ x0dx0ax0dx0a------沒有成功「回滾」執行rollback x0dx0amysql> start transaction; //開啟事務 x0dx0aQuery OK, 0 rows affected (0.00 sec) x0dx0ax0dx0amysql> update bank set money=money+500 where name='shaotuo' x0dx0aQuery OK, 1 row affected (0.00 sec) x0dx0aRows matched: 1 Changed: 1 Warnings: 0 x0dx0ax0dx0amysql> update bank set moey=money-500 where name='laohu' x0dx0aERROR 1054 (42S22): Unknown column 'moey' in 'field list' x0dx0amysql> rollback; //只要有一個不成功,執行rollback操作 x0dx0aQuery OK, 0 rows affected (0.01 sec) x0dx0ax0dx0amysql> select*from bank; x0dx0a+---------+--------+ x0dx0a| name | money | x0dx0a+---------+--------+ x0dx0a| shaotuo | 1000.0 | x0dx0a| laohu | 5000.0 | x0dx0a+---------+--------+ x0dx0a------成功之後 進行commit操作 x0dx0amysql> start transaction; //開啟事務 x0dx0aQuery OK, 0 rows affected (0.00 sec) x0dx0ax0dx0amysql> update bank set money=money+500 where name='shaotuo' x0dx0aQuery OK, 1 row affected (0.01 sec) x0dx0aRows matched: 1 Changed: 1 Warnings: 0 x0dx0ax0dx0amysql> update bank set money=money-500 where name='laohu' x0dx0aQuery OK, 1 row affected (0.00 sec) x0dx0aRows matched: 1 Changed: 1 Warnings: 0 x0dx0ax0dx0amysql> commit; //兩個都成功後執行commit(只要不執行commit,sql語句不會對真實的資料庫造成影響) x0dx0aQuery OK, 0 rows affected (0.05 sec) x0dx0ax0dx0amysql> select*from bank; x0dx0a+---------+--------+ x0dx0a| name | money | x0dx0a+---------+--------+ x0dx0a| shaotuo | 1500.0 | x0dx0a| laohu | 4500.0 | x0dx0a+---------+--------+
㈩ Mysql某個表有近千萬數據,CRUD比較慢,如何優化
數據千萬級別之多,佔用的存儲空間也比較大,可想而知它不會存儲在一塊連續的物理空間上,而是鏈式存儲在多個碎片的物理空間上。可能對於長字元串的比較,就用更多的時間查找與比較,這就導致用更多的時間。
可以做表拆分,減少單表欄位數量,優化表結構。
在保證主鍵有效的情況下,檢查主鍵索引的欄位順序,使得查詢語句中條件的欄位順序和主鍵索引的欄位順序保持一致。
主要兩種拆分 垂直拆分,水平拆分。
垂直分表
也就是「大表拆小表」,基於列欄位進行的。一般是表中的欄位較多,將不常用的, 數據較大,長度較長(比如text類型欄位)的拆分到「擴展表「。 一般是針對 那種 幾百列的大表,也避免查詢時,數據量太大造成的「跨頁」問題。
垂直分庫針對的是一個系統中的不同業務進行拆分,比如用戶User一個庫,商品Proct一個庫,訂單Order一個庫。 切分後,要放在多個伺服器上,而不是一個伺服器上。為什麼? 我們想像一下,一個購物網站對外提供服務,會有用戶,商品,訂單等的CRUD。沒拆分之前, 全部都是落到單一的庫上的,這會讓資料庫的單庫處理能力成為瓶頸。按垂直分庫後,如果還是放在一個資料庫伺服器上, 隨著用戶量增大,這會讓單個資料庫的處理能力成為瓶頸,還有單個伺服器的磁碟空間,內存,tps等非常吃緊。 所以我們要拆分到多個伺服器上,這樣上面的問題都解決了,以後也不會面對單機資源問題。
資料庫業務層面的拆分,和服務的「治理」,「降級」機制類似,也能對不同業務的數據分別的進行管理,維護,監控,擴展等。 資料庫往往最容易成為應用系統的瓶頸,而資料庫本身屬於「有狀態」的,相對於Web和應用伺服器來講,是比較難實現「橫向擴展」的。 資料庫的連接資源比較寶貴且單機處理能力也有限,在高並發場景下,垂直分庫一定程度上能夠突破IO、連接數及單機硬體資源的瓶頸。
水平分表
針對數據量巨大的單張表(比如訂單表),按照某種規則(RANGE,HASH取模等),切分到多張表裡面去。 但是這些表還是在同一個庫中,所以庫級別的資料庫操作還是有IO瓶頸。不建議採用。
水平分庫分表
將單張表的數據切分到多個伺服器上去,每個伺服器具有相應的庫與表,只是表中數據集合不同。 水平分庫分表能夠有效的緩解單機和單庫的性能瓶頸和壓力,突破IO、連接數、硬體資源等的瓶頸。
水平分庫分表切分規則
1. RANGE
從0到10000一個表,10001到20000一個表;
2. HASH取模
一個商場系統,一般都是將用戶,訂單作為主表,然後將和它們相關的作為附表,這樣不會造成跨庫事務之類的問題。 取用戶id,然後hash取模,分配到不同的資料庫上。
3. 地理區域
比如按照華東,華南,華北這樣來區分業務,七牛雲應該就是如此。
4. 時間
按照時間切分,就是將6個月前,甚至一年前的數據切出去放到另外的一張表,因為隨著時間流逝,這些表的數據 被查詢的概率變小,所以沒必要和「熱數據」放在一起,這個也是「冷熱數據分離」。
分庫分表後面臨的問題
事務支持
分庫分表後,就成了分布式事務了。如果依賴資料庫本身的分布式事務管理功能去執行事務,將付出高昂的性能代價; 如果由應用程序去協助控制,形成程序邏輯上的事務,又會造成編程方面的負擔。
跨庫join
只要是進行切分,跨節點Join的問題是不可避免的。但是良好的設計和切分卻可以減少此類情況的發生。解決這一問題的普遍做法是分兩次查詢實現。在第一次查詢的結果集中找出關聯數據的id,根據這些id發起第二次請求得到關聯數據。
跨節點的count,order by,group by以及聚合函數問題
這些是一類問題,因為它們都需要基於全部數據集合進行計算。多數的代理都不會自動處理合並工作。解決方案:與解決跨節點join問題的類似,分別在各個節點上得到結果後在應用程序端進行合並。和join不同的是每個結點的查詢可以並行執行,因此很多時候它的速度要比單一大錶快很多。但如果結果集很大,對應用程序內存的消耗是一個問題。
數據遷移,容量規劃,擴容等問題
來自淘寶綜合業務平台團隊,它利用對2的倍數取余具有向前兼容的特性(如對4取余得1的數對2取余也是1)來分配數據,避免了行級別的數據遷移,但是依然需要進行表級別的遷移,同時對擴容規模和分表數量都有限制。總得來說,這些方案都不是十分的理想,多多少少都存在一些缺點,這也從一個側面反映出了Sharding擴容的難度。
ID問題
一旦資料庫被切分到多個物理結點上,我們將不能再依賴資料庫自身的主鍵生成機制。一方面,某個分區資料庫自生成的ID無法保證在全局上是唯一的;另一方面,應用程序在插入數據之前需要先獲得ID,以便進行SQL路由.
一些常見的主鍵生成策略
UUID
使用UUID作主鍵是最簡單的方案,但是缺點也是非常明顯的。由於UUID非常的長,除佔用大量存儲空間外,最主要的問題是在索引上,在建立索引和基於索引進行查詢時都存在性能問題。
Twitter的分布式自增ID演算法Snowflake
在分布式系統中,需要生成全局UID的場合還是比較多的,twitter的snowflake解決了這種需求,實現也還是很簡單的,除去配置信息,核心代碼就是毫秒級時間41位 機器ID 10位 毫秒內序列12位。
跨分片的排序分頁
一般來講,分頁時需要按照指定欄位進行排序。當排序欄位就是分片欄位的時候,我們通過分片規則可以比較容易定位到指定的分片,而當排序欄位非分片欄位的時候,情況就會變得比較復雜了。為了最終結果的准確性,我們需要在不同的分片節點中將數據進行排序並返回,並將不同分片返回的結果集進行匯總和再次排序,最後再返回給用戶。