欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

mysql的3種分表方案

 更新時(shí)間:2014年05月13日 10:13:39   作者:  
這篇文章主要介紹了mysql的3種分表方案,先從為什么要分表說(shuō)起,然后分析了3種方法的優(yōu)劣勢(shì),最后做了一個(gè)總結(jié),需要的朋友可以參考下

一、先說(shuō)一下為什么要分表:
當(dāng)一張的數(shù)據(jù)達(dá)到幾百萬(wàn)時(shí),你查詢一次所花的時(shí)間會(huì)變多,如果有聯(lián)合查詢的話,有可能會(huì)死在那兒了。分表的目的就在于此,減小數(shù)據(jù)庫(kù)的負(fù)擔(dān),縮短查詢時(shí)間。

根據(jù)個(gè)人經(jīng)驗(yàn),mysql執(zhí)行一個(gè)sql的過(guò)程如下:
1、接收到sql; 
2、把sql放到排隊(duì)隊(duì)列中;
3、執(zhí)行sql; 
4、返回執(zhí)行結(jié)果。
在這個(gè)執(zhí)行過(guò)程中最花時(shí)間在什么地方呢?第一,是排隊(duì)等待的時(shí)間,第二,sql的執(zhí)行時(shí)間。其實(shí)這二個(gè)是一回事,等待的同時(shí),肯定有sql在執(zhí)行。所以我們要縮短sql的執(zhí)行時(shí)間。

mysql中有一種機(jī)制是表鎖定和行鎖定,為什么要出現(xiàn)這種機(jī)制,是為了保證數(shù)據(jù)的完整性,我舉個(gè)例子來(lái)說(shuō)吧,如果有二個(gè)sql都要修改同一張表的同一條數(shù)據(jù),這個(gè)時(shí)候怎么辦呢,是不是二個(gè)sql都可以同時(shí)修改這條數(shù)據(jù)呢?很顯然mysql對(duì)這種情況的處理是,一種是表鎖定(myisam存儲(chǔ)引擎),一個(gè)是行鎖定(innodb存儲(chǔ)引擎)。表鎖定表示你們都不能對(duì)這張表進(jìn)行操作,必須等我對(duì)表操作完才行。行鎖定也一樣,別的sql必須等我對(duì)這條數(shù)據(jù)操作完了,才能對(duì)這條數(shù)據(jù)進(jìn)行操作。如果數(shù)據(jù)太多,一次執(zhí)行的時(shí)間太長(zhǎng),等待的時(shí)間就越長(zhǎng),這也是我們?yōu)槭裁匆直淼脑颉?nbsp; 

二、分表

1,做mysql集群,例如:利用mysql cluster ,mysql proxy,mysql replication,drdb等等

有人會(huì)問(wèn)mysql集群,根分表有什么關(guān)系嗎?雖然它不是實(shí)際意義上的分表,但是它啟到了分表的作用,做集群的意義是什么呢?為一個(gè)數(shù)據(jù)庫(kù)減輕負(fù)擔(dān),說(shuō)白了就是減少sql排隊(duì)隊(duì)列中的sql的數(shù)量,舉個(gè)例子:有10個(gè)sql請(qǐng)求,如果放在一個(gè)數(shù)據(jù)庫(kù)服務(wù)器的排隊(duì)隊(duì)列中,他要等很長(zhǎng)時(shí)間,如果把這10個(gè)sql請(qǐng)求,分配到5個(gè)數(shù)據(jù)庫(kù)服務(wù)器的排隊(duì)隊(duì)列中,一個(gè)數(shù)據(jù)庫(kù)服務(wù)器的隊(duì)列中只有2個(gè),這樣等待時(shí)間是不是大大的縮短了呢?這已經(jīng)很明顯了。所以我把它列到了分表的范圍以內(nèi),我做過(guò)一些mysql的集群:

linux mysql proxy 的安裝,配置,以及讀寫分離
mysql replication 互為主從的安裝及配置,以及數(shù)據(jù)同步
優(yōu)點(diǎn):擴(kuò)展性好,沒(méi)有多個(gè)分表后的復(fù)雜操作(php代碼)
缺點(diǎn):?jiǎn)蝹€(gè)表的數(shù)據(jù)量還是沒(méi)有變,一次操作所花的時(shí)間還是那么多,硬件開(kāi)銷大。

2,預(yù)先估計(jì)會(huì)出現(xiàn)大數(shù)據(jù)量并且訪問(wèn)頻繁的表,將其分為若干個(gè)表

這種預(yù)估大差不差的,論壇里面發(fā)表帖子的表,時(shí)間長(zhǎng)了這張表肯定很大,幾十萬(wàn),幾百萬(wàn)都有可能。 聊天室里面信息表,幾十個(gè)人在一起一聊一個(gè)晚上,時(shí)間長(zhǎng)了,這張表的數(shù)據(jù)肯定很大。像這樣的情況很多。所以這種能預(yù)估出來(lái)的大數(shù)據(jù)量表,我們就事先分出個(gè)N個(gè)表,這個(gè)N是多少,根據(jù)實(shí)際情況而定。以聊天信息表為例:

我事先建100個(gè)這樣的表,message_00,message_01,message_02……….message_98,message_99.然后根據(jù)用戶的ID來(lái)判斷這個(gè)用戶的聊天信息放到哪張表里面,你可以用hash的方式來(lái)獲得,可以用求余的方式來(lái)獲得,方法很多,各人想各人的吧。下面用hash的方法來(lái)獲得表名:

復(fù)制代碼 代碼如下:

<?php
function get_hash_table($table,$userid) {
 $str = crc32($userid);
 if($str<0){
  $hash = "0".substr(abs($str), 0, 1);
 }else{
  $hash = substr($str, 0, 2);
 }
 return $table."_".$hash;
}   

echo get_hash_table('message' , 'user18991');     //結(jié)果為message_10
echo get_hash_table('message' , 'user34523');    //結(jié)果為message_13
?> 

說(shuō)明一下,上面的這個(gè)方法,告訴我們user18991這個(gè)用戶的消息都記錄在message_10這張表里,user34523這個(gè)用戶的消息都記錄在message_13這張表里,讀取的時(shí)候,只要從各自的表中讀取就行了。

優(yōu)點(diǎn):避免一張表出現(xiàn)幾百萬(wàn)條數(shù)據(jù),縮短了一條sql的執(zhí)行時(shí)間

缺點(diǎn):當(dāng)一種規(guī)則確定時(shí),打破這條規(guī)則會(huì)很麻煩,上面的例子中我用的hash算法是crc32,如果我現(xiàn)在不想用這個(gè)算法了,改用md5后,會(huì)使同一個(gè)用戶的消息被存儲(chǔ)到不同的表中,這樣數(shù)據(jù)亂套了。擴(kuò)展性很差。

3,利用merge存儲(chǔ)引擎來(lái)實(shí)現(xiàn)分表

我覺(jué)得這種方法比較適合,那些沒(méi)有事先考慮,而已經(jīng)出現(xiàn)了得,數(shù)據(jù)查詢慢的情況。這個(gè)時(shí)候如果要把已有的大數(shù)據(jù)量表分開(kāi)比較痛苦,最痛苦的事就是改代碼,因?yàn)槌绦蚶锩娴膕ql語(yǔ)句已經(jīng)寫好了,現(xiàn)在一張表要分成幾十張表,甚至上百?gòu)埍?,這樣sql語(yǔ)句是不是要重寫呢?舉個(gè)例子,我很喜歡舉例子

mysql>show engines;的時(shí)候你會(huì)發(fā)現(xiàn)mrg_myisam其實(shí)就是merge。

復(fù)制代碼 代碼如下:

mysql> CREATE TABLE IF NOT EXISTS `user1` (
 ->   `id` int(11) NOT NULL AUTO_INCREMENT,
 ->   `name` varchar(50) DEFAULT NULL,
 ->   `sex` int(1) NOT NULL DEFAULT '0',
 ->   PRIMARY KEY (`id`)
 -> ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
Query OK, 0 rows affected (0.05 sec)   

mysql> CREATE TABLE IF NOT EXISTS `user2` (
 ->   `id` int(11) NOT NULL AUTO_INCREMENT,
 ->   `name` varchar(50) DEFAULT NULL,
 ->   `sex` int(1) NOT NULL DEFAULT '0',
 ->   PRIMARY KEY (`id`)
 -> ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
Query OK, 0 rows affected (0.01 sec)   

mysql> INSERT INTO `user1` (`name`, `sex`) VALUES('張映', 0);
Query OK, 1 row affected (0.00 sec)   

mysql> INSERT INTO `user2` (`name`, `sex`) VALUES('tank', 1);
Query OK, 1 row affected (0.00 sec)   

mysql> CREATE TABLE IF NOT EXISTS `alluser` (
 ->   `id` int(11) NOT NULL AUTO_INCREMENT,
 ->   `name` varchar(50) DEFAULT NULL,
 ->   `sex` int(1) NOT NULL DEFAULT '0',
 ->   INDEX(id)
 -> ) TYPE=MERGE UNION=(user1,user2) INSERT_METHOD=LAST AUTO_INCREMENT=1 ;
Query OK, 0 rows affected, 1 warning (0.00 sec)   

mysql> select id,name,sex from alluser;
+----+--------+-----+
| id | name   | sex |
+----+--------+-----+
|  1 | 張映    |   0 |
|  1 | tank   |   1 |
+----+--------+-----+
2 rows in set (0.00 sec)   

mysql> INSERT INTO `alluser` (`name`, `sex`) VALUES('tank2', 0);
Query OK, 1 row affected (0.00 sec)   

mysql> select id,name,sex from user2
 -> ;
+----+-------+-----+
| id | name  | sex |
+----+-------+-----+
|  1 | tank  |   1 |
|  2 | tank2 |   0 |
+----+-------+-----+
2 rows in set (0.00 sec) 

mysql> CREATE TABLE IF NOT EXISTS `user1` (  ->   `id` int(11) NOT NULL AUTO_INCREMENT,  ->   `name` varchar(50) DEFAULT NULL,  ->   `sex` int(1) NOT NULL DEFAULT '0',  ->   PRIMARY KEY (`id`)  -> ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; Query OK, 0 rows affected (0.05 sec)  mysql> CREATE TABLE IF NOT EXISTS `user2` (  ->   `id` int(11) NOT NULL AUTO_INCREMENT,  ->   `name` varchar(50) DEFAULT NULL,  ->   `sex` int(1) NOT NULL DEFAULT '0',  ->   PRIMARY KEY (`id`)  -> ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; Query OK, 0 rows affected (0.01 sec)  mysql> INSERT INTO `user1` (`name`, `sex`) VALUES('張映', 0); Query OK, 1 row affected (0.00 sec)  mysql> INSERT INTO `user2` (`name`, `sex`) VALUES('tank', 1); Query OK, 1 row affected (0.00 sec)  mysql> CREATE TABLE IF NOT EXISTS `alluser` (  ->   `id` int(11) NOT NULL AUTO_INCREMENT,  ->   `name` varchar(50) DEFAULT NULL,  ->   `sex` int(1) NOT NULL DEFAULT '0',  ->   INDEX(id)  -> ) TYPE=MERGE UNION=(user1,user2) INSERT_METHOD=LAST AUTO_INCREMENT=1 ; Query OK, 0 rows affected, 1 warning (0.00 sec)  mysql> select id,name,sex from alluser;
+----+--------+-----+
| id | name   | sex |
+----+--------+-----+
|  1 |  張映   |   0 |
|  1 | tank   |   1 |
+----+--------+-----+
2 rows in set (0.00 sec)

mysql> INSERT INTO `alluser` (`name`, `sex`) VALUES('tank2', 0); Query OK, 1 row affected (0.00 sec)  mysql> select id,name,sex from user2  -> ;

+----+-------+-----+
| id | name  | sex |
+----+-------+-----+
|  1 | tank  |   1 |
|  2 | tank2 |   0 |
+----+-------+-----+
2 rows in set (0.00 sec)


從上面的操作中,我不知道你有沒(méi)有發(fā)現(xiàn)點(diǎn)什么?假如我有一張用戶表user,有50W條數(shù)據(jù),現(xiàn)在要拆成二張表user1和user2,每張表25W條數(shù)據(jù),
復(fù)制代碼 代碼如下:

INSERT INTO user1(user1.id,user1.name,user1.sex)SELECT (user.id,user.name,user.sex)FROM user where user.id <= 250000

INSERT INTO user2(user2.id,user2.name,user2.sex)SELECT (user.id,user.name,user.sex)FROM user where user.id > 250000


這樣我就成功的將一張user表,分成了二個(gè)表,這個(gè)時(shí)候有一個(gè)問(wèn)題,代碼中的sql語(yǔ)句怎么辦,以前是一張表,現(xiàn)在變成二張表了,代碼改動(dòng)很大,這樣給程序員帶來(lái)了很大的工作量,有沒(méi)有好的辦法解決這一點(diǎn)呢?辦法是把以前的user表備份一下,然后刪除掉,上面的操作中我建立了一個(gè)alluser表,只把這個(gè)alluser表的表名改成user就行了。但是,不是所有的mysql操作都能用的

a,如果你使用 alter table 來(lái)把 merge 表變?yōu)槠渌眍愋?,到底層表的映射就被丟失了。取而代之的,來(lái)自底層 myisam 表的行被復(fù)制到已更換的表中,該表隨后被指定新類型。

b,網(wǎng)上看到一些說(shuō)replace不起作用,我試了一下可以起作用的。暈一個(gè)先

復(fù)制代碼 代碼如下:

mysql> UPDATE alluser SET sex=REPLACE(sex, 0, 1) where id=2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0   

mysql> select * from alluser;
+----+--------+-----+
| id | name   | sex |
+----+--------+-----+
|  1 | 張映    |   0 |
|  1 | tank   |   1 |
|  2 | tank2  |   1 |
+----+--------+-----+
3 rows in set (0.00 sec) 

mysql> UPDATE alluser SET sex=REPLACE(sex, 0, 1) where id=2; Query OK, 1 row affected (0.00 sec) Rows matched: 1  Changed: 1  Warnings: 0  mysql> select * from alluser;
 +----+--------+-----+
 | id | name   | sex |
 +----+--------+-----+
 |  1 | 張映    |   0 |
 |  1 | tank   |   1 |
 |  2 | tank2  |   1 |
 +----+--------+-----+
 3 rows in set (0.00 sec)



c,一個(gè) merge 表不能在整個(gè)表上維持 unique 約束。當(dāng)你執(zhí)行一個(gè) insert,數(shù)據(jù)進(jìn)入第一個(gè)或者最后一個(gè) myisam 表(取決于 insert_method 選項(xiàng)的值)。mysql 確保唯一鍵值在那個(gè) myisam 表里保持唯一,但不是跨集合里所有的表。

d,當(dāng)你創(chuàng)建一個(gè) merge 表之時(shí),沒(méi)有檢查去確保底層表的存在以及有相同的機(jī)構(gòu)。當(dāng) merge 表被使用之時(shí),mysql 檢查每個(gè)被映射的表的記錄長(zhǎng)度是否相等,但這并不十分可靠。如果你從不相似的 myisam 表創(chuàng)建一個(gè) merge 表,你非常有可能撞見(jiàn)奇怪的問(wèn)題。

c和d在網(wǎng)上看到的,沒(méi)有測(cè)試,大家試一下吧。

優(yōu)點(diǎn):擴(kuò)展性好,并且程序代碼改動(dòng)的不是很大

缺點(diǎn):這種方法的效果比第二種要差一點(diǎn)

三、總結(jié)一下

上面提到的三種方法,我實(shí)際做過(guò)二種,第一種和第二種。第三種沒(méi)有做過(guò),所以說(shuō)的細(xì)一點(diǎn)。哈哈。做什么事都有一個(gè)度,超過(guò)個(gè)度就過(guò)變得很差,不能一味的做數(shù)據(jù)庫(kù)服務(wù)器集群,硬件是要花錢買的,也不要一味的分表,分出來(lái)1000表,mysql的存儲(chǔ)歸根到底還以文件的形勢(shì)存在硬盤上面,一張表對(duì)應(yīng)三個(gè)文件,1000個(gè)分表就是對(duì)應(yīng)3000個(gè)文件,這樣檢索起來(lái)也會(huì)變的很慢。我的建議是

方法1和方法2結(jié)合的方式來(lái)進(jìn)行分表
方法1和方法3結(jié)合的方式來(lái)進(jìn)行分表

我的二個(gè)建議適合不同的情況,根據(jù)個(gè)人情況而定,我覺(jué)得會(huì)有很多人選擇方法1和方法3結(jié)合的方式

相關(guān)文章

  • 詳細(xì)介紹基于MySQL的搜索引擎MySQL-Fullltext

    詳細(xì)介紹基于MySQL的搜索引擎MySQL-Fullltext

    這篇文章主要詳細(xì)介紹基于MySQL的搜索引擎MySQL-Fullltext,需要用到C和C#以及JavaScript的知識(shí),屬于MySQL的高階應(yīng)用,需要的朋友可以參考下
    2015-04-04
  • Mysql 5.7.19 免安裝版配置方法教程詳解(64位)

    Mysql 5.7.19 免安裝版配置方法教程詳解(64位)

    這篇文章主要介紹了Mysql 5.7.19 免安裝版配置方法教程詳解,需要的朋友可以參考下
    2017-08-08
  • 詳解DBeaver連接MySQL8以上版本以及解決可能遇到的問(wèn)題

    詳解DBeaver連接MySQL8以上版本以及解決可能遇到的問(wèn)題

    這篇文章主要介紹了DBeaver連接MySQL8以上版本以及解決可能遇到的問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • 數(shù)據(jù)庫(kù)sql語(yǔ)句優(yōu)化

    數(shù)據(jù)庫(kù)sql語(yǔ)句優(yōu)化

    今天小編就為大家分享一篇關(guān)于數(shù)據(jù)庫(kù)sql語(yǔ)句優(yōu)化,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-01-01
  • Navicat出現(xiàn)無(wú)法遠(yuǎn)程連接MySql服務(wù)器問(wèn)題的解決辦法

    Navicat出現(xiàn)無(wú)法遠(yuǎn)程連接MySql服務(wù)器問(wèn)題的解決辦法

    這篇文章主要介紹了Navicat出現(xiàn)無(wú)法遠(yuǎn)程連接MySql服務(wù)器問(wèn)題的解決辦法,文章通過(guò)思路判斷出現(xiàn)問(wèn)題的情況,然后進(jìn)行逐一排查,確定問(wèn)題出現(xiàn)的原因并給出解決辦法,本文對(duì)此問(wèn)題的解決介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-08-08
  • 實(shí)現(xiàn)mysql級(jí)聯(lián)復(fù)制的方法示例

    實(shí)現(xiàn)mysql級(jí)聯(lián)復(fù)制的方法示例

    這篇文章主要介紹了實(shí)現(xiàn)mysql級(jí)聯(lián)復(fù)制的方法示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05
  • mysql 5.6.13 免安裝版配置方法詳解

    mysql 5.6.13 免安裝版配置方法詳解

    這篇文章主要介紹了mysql 5.6.13 免安裝版配置的方法,今天小編把配置方法分享到腳本之家平臺(tái)供大家參考下
    2016-10-10
  • log引起的mysql不能啟動(dòng)的解決方法

    log引起的mysql不能啟動(dòng)的解決方法

    今天服務(wù)器掛了原來(lái)服務(wù)器的硬盤進(jìn)行了數(shù)據(jù)轉(zhuǎn)移 弄到mysql的時(shí)候發(fā)現(xiàn)里面log日志文件高達(dá)900MB
    2008-07-07
  • MySQL數(shù)據(jù)庫(kù)查詢性能優(yōu)化策略

    MySQL數(shù)據(jù)庫(kù)查詢性能優(yōu)化策略

    這篇文章主要介紹了MySQL數(shù)據(jù)庫(kù)查詢性能優(yōu)化的策略,幫助大家的工作學(xué)習(xí)提高M(jìn)ySQL數(shù)據(jù)庫(kù)的性能,感興趣的朋友可以了解下
    2020-08-08
  • MySQL安裝服務(wù)時(shí)提示:Install/Remove?of?the?Service?Denied解決

    MySQL安裝服務(wù)時(shí)提示:Install/Remove?of?the?Service?Denied解決

    今天給新電腦安裝了mysql,本來(lái)好好的,卻報(bào)了個(gè)bug,就記錄下吧,這篇文章主要給大家介紹了關(guān)于MySQL安裝服務(wù)時(shí)提示:Install/Remove?of?the?Service?Denied的解決辦法,需要的朋友可以參考下
    2023-03-03

最新評(píng)論