生活随笔
收集整理的這篇文章主要介紹了
mysql分库分表实战及php代码操作完整实例
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
當單表達到幾千萬時,查詢一次要很久,如果有聯(lián)合查詢,有可能會死在那 分庫分表主要就是解決這個問題,減小數(shù)據(jù)庫的負擔,縮短查詢時間 分庫: 1)按功能分 用戶類庫、商品類庫、訂單類庫、日志類、統(tǒng)計類庫... 1)按地區(qū)分 每個城市或省市一個同樣的庫,加上后綴或前綴如:db_click_bj、db_click_sh... 分表: 1、橫向分表 解決表記錄太大問題 1)按某個字段分, 如:discuz的附件表分成10個附件分表pre_forum_attachment_0到pre_forum_attachment_9,還有1個附件索引表pre_forum_attachment存儲tid和附件id關系 根據(jù)主題的tid最后一位來決定附件要保存在哪個分表, 2)按日期分表 一些日志、統(tǒng)計類的可以按年、月、日、周分表 如:點擊量統(tǒng)計click_201601、click_201602 3)使用mysql的merge 先把分表創(chuàng)建好,然后創(chuàng)建總表指定engine= MERGE UNION=(table1,table2) INSERT_METHOD = LAST;
2、縱向分表 解決列過多問題 1)經常組合查詢的列放在一個表,常用字段的表可考慮Memory引擎 2)不經常使用的字段單獨成表 3)把text、blob等大字段拆分放在附表 如:phpcms的文章表分成主表v9_news和從表v9_news_data,主表存標題、關鍵字、瀏覽量等,從表存具體內容、模板等 很多主流mvc框架都提供了切換數(shù)據(jù)庫訪問方法
thinkphp切換數(shù)據(jù)庫
$this->db(1,"mysql://root:123456@localhost:3306/test")->query("查詢sql");//數(shù)據(jù)庫連接信息可放在配置文件 $this->db(1)->query("查詢sql");//下次直接使用編號1定位 分表的話 在查詢前先根據(jù)分表規(guī)則把表名查出
這里用兩臺機子簡單以同個業(yè)務庫分庫,同個表分表,演示插入、查詢如何定位庫和表并最終成功執(zhí)行
兩臺機子:
server1:192.168.1.198
server2:192.168.1.199
兩臺機子都執(zhí)行下面操作
1、先創(chuàng)建10個數(shù)據(jù)庫,每個數(shù)據(jù)庫10個表
當然也可以改成百庫百表,也可手動創(chuàng)建,我為了方便寫了個腳本批量創(chuàng)建
create.php [php]?view plaincopy
<?php?? ini_set('memory_limit',?'-1');?? $con=mysql_connect("192.168.1.198","open","123456");?? if($con){????? ????for($i=0;$i<10;$i++){?? ????????$sql="drop?database?cloude_{$i};";?? ????????mysql_query($sql);?? ????????$sql="create?database?cloude_{$i}?default?character?set?utf8?collate?utf8_general_ci;";?? ????????$do=mysql_query($sql,$con)or?die(mysql_error());?? ????????if($do){?? ????????????mysql_select_db("cloude_{$i}",$con);?? ????????????mysql_query("set?name?gtf8");?? ????????????for($j=0;$j<10;$j++){?????????? ????????????????$sql="drop?table?if?exists?user_{$j};";?? ????????????????mysql_query($sql);?? ????????????????$sql="create?table?user_{$j}?? ????????????????(?? ????????????????????id?char(36)?not?null?primary?key,?? ????????????????????name?char(15)?not?null?default?'',?? ????????????????????password?char(32)?not?null?default?'',?? ????????????????????sex?char(1)?not?null?default?'男'?? ????????????????)engine=InnoDB;";?? ????????????????$do=mysql_query($sql,$con)?or?die(mysql_error());?? ????????????????if($do){?? ?????????????????????? ????????????????}else{?? ?????????????????????? ????????????????}?? ????????????}?? ????????}?? ????}?? }else{?? ????echo?"connect?error!!!!";?? }?? 2、分庫分表路由實現(xiàn) Config.PHP
[php]?view plaincopy
<?php?? class?Config{???? ????public?$dsn;???? ????public?$user;???? ????public?$password;???? ????public?$dbname;??? ????public?$table;??? ????private?static?$config;?? ????private?static?$configFile?=?'mysql.php';??? ?????? ????public?function?__construct($dbname,?$table,?$id?=?0){???? ????????if?(is_null(static::$config))?{???? ????????????$config?=?include(static::$configFile);???? ????????????static::$config?=?$config;???? ????????}???? ?????? ????????$config?=?static::$config;???? ????????if?(isset($config['shared'])?&&?isset($config['shared'][$dbname]))?{???? ????????????$dbconfig?=?$config['shared'][$dbname];???? ????????????$id?=?is_numeric($id)???(int)$id?:?crc32($id);???? ????????????$database_id?=?($id?/?$dbconfig['database_split'][0])?%?$dbconfig['database_split'][1];???? ????????????$table_id?=?($id?/?$dbconfig['table_split'][0])?%?$dbconfig['table_split'][1];???? ?????? ????????????foreach?($dbconfig['host']?as?$key?=>?$conf)?{???? ????????????????list($from,?$to)?=?explode('-',?$key);???? ????????????????if?($from?<=?$database_id?&&?$database_id?<=?$to)?{???? ????????????????????$the_config?=?$conf;???? ????????????????}???? ????????????}???? ?????? ????????????$this->dbname?=?$dbname?.?'_'?.?$database_id;???? ????????????$this->table?=?$table?.?'_'?.?$table_id;???? ????????}?else?{???? ????????????$this->dbname?=?$dbname;???? ????????????$this->table?=?$table;???? ????????????$the_config?=?$config['db'][$dbname];???? ????????}???? ????????$c?=?$the_config;???? ????????if?(isset($c['unix_socket'])?&&?$c['unix_socket'])?{???? ????????????$this->dsn?=?sprintf('mysql:dbname=%s;unix_socket=%s',?$this->dbname,?$c['unix_socket']);???? ????????}?else?{???? ????????????$this->dsn?=?sprintf('mysql:dbname=%s;host=%s;port=%s',?$this->dbname,?$c['host'],?$c['port']);???? ????????}???? ????????$this->user?=?$c['user'];???? ????????$this->password?=?$c['password'];???? ????}???? ?????? }??
3、數(shù)據(jù)庫配置文件 mysql.php [php]?view plaincopy
<?php?? $default?=?array(???? ????'unix_socket'?=>?null,???? ????'host'?=>?'192.168.1.198',???? ????'port'?=>?'3306',???? ????'user'?=>?'open',???? ????'password'?=>?'123456',???? );???? $db_199?=?array(???? ????'unix_socket'?=>?null,???? ????'host'?=>?'192.168.1.199',???? ????'port'?=>?'3306',???? ????'user'?=>?'open',???? ????'password'?=>?'123456',???? );??????? $config?=?array(???? ?????? ????'db'?=>?array(???? ????????'hadoop'?=>?$default,???? ????),???? ?????? ????'shared'?=>?array(???? ????????'cloude'?=>?array(???? ????????????'host'?=>?array(???? ????????????????? ? ??? ????????????????'0-4'?=>?$default,???? ????????????????? ? ??? ????????????????'5-9'?=>?$db_199,????? ?????? ????????????),???? ?????? ?????????????? ????????????? ? ? ? ? ??? ????????????'database_split'?=>?array(1,?10),???? ????????????'table_split'?=>?array(10,?10),???? ????????),???? ????),???? );???? return?$config;?? 4、模型類操作數(shù)據(jù)庫 Model.PHP
[php]?view plaincopy
<?php?? require_once?'Config.php';?? class?Model{???? ????public?$config;??????? ????public?$connection;??? ????protected?$dbnamePrefix;??? ????protected?$tablePrefix;???? ????protected?$dbname;???? ????protected?$table;????? ?????? ????public?function?__construct($id){???? ????????$this->config?=?new?Config($this->dbnamePrefix,?$this->tablePrefix,?$id);???????????????????? ????????$this->connection?=?new?Pdo($this->config->dsn,?$this->config->user,?$this->config->password);?? ????????$this->connection->exec("set?names?utf8");????? ????????$this->dbname?=?$this->config->dbname;?? ????????$this->table?=?$this->config->table;???? ????}???? ?????? ????public?function?update(array?$data,?array?$where?=?array()){???? ?????? ????}???? ?????? ????public?function?select(array?$condition){??? ????????$sqlwhere='';?? ????????if(!empty($condition)){????? ????????????foreach?($condition?as?$field?=>?$value)?{???? ????????????????$where[]?=?'`'.$field.'`='."'".addslashes($value)."'";???? ????????????}???? ????????????$sqlwhere?.=?'?'.implode('?and?',?$where);????? ????????}?? ????????$sql="select?*?from?".$this->dbname.'.'.$this->table;?? ????????if($sqlwhere){?? ????????????$sql.="?where?$sqlwhere";?? ????????}?? ????????$res=$this->connection->query($sql);?? ????????$data['data']=$res->fetchAll(PDO::FETCH_ASSOC);?? ????????$data['info']=array("dsn"=>$this->config->dsn,"dbname"=>$this->dbname,"table"=>$this->table,"sql"=>$sql);?? ????????return?$data;????? ????}???? ????public?function?insert(array?$arrData)?{?? ????????$name?=?$values?=?'';?? ????????$flag?=?$flagV?=?1;?? ????????$true?=?is_array(?current($arrData)?);?? ????????if($true)?{?? ?????????????? ????????????foreach($arrData?as?$arr)?{?? ????????????????$values?.=?$flag???'('?:?',(';?? ????????????????foreach($arr?as?$key?=>?$value)?{?? ????????????????????if($flagV)?{?? ????????????????????????if($flag)?$name?.=?"$key";?? ????????????????????????$values?.=?"'$value'";?? ????????????????????????$flagV?=?0;?? ????????????????????}?else?{?? ????????????????????????if($flag)?$name?.=?",$key";?? ????????????????????????$values?.=?",'$value'";?? ????????????????????}?? ????????????????}?? ????????????????$values?.=?')?';?? ????????????????$flag?=?0;?? ????????????????$flagV?=?1;?? ????????????}?? ????????}?else?{?? ?????????????? ????????????foreach($arrData?as?$key?=>?$value)?{?? ????????????????if($flagV)?{?? ????????????????????$name?=?"$key";?? ????????????????????$values?=?"('$value'";?? ????????????????????$flagV?=?0;?? ????????????????}?else?{?? ????????????????????$name?.=?",$key";?? ????????????????????$values?.=?",'$value'";?? ????????????????}?? ????????????}?? ????????????$values?.=?")?";?? ????????}?? ??????????? ????????$sql?=?"insert?into?".$this->dbname.'.'.$this->table."?($name)?values?$values";?? ????????if(?($rs?=?$this->connection->exec($sql)?)?>?0?)?{?? ????????????return?array("dsn"=>$this->config->dsn,"dbname"=>$this->dbname,"table"=>$this->table,"sql"=>$sql);?? ????????}?? ????????return?false;?? ????}?? ????public?function?query($sql){???? ????????return?$this->connection->query($sql);???? ????}???? }??
5、測試 使用主鍵id作為分表字段,那最好就不要使用自增了,可使用uuid
User.php
[php]?view plaincopy
<?php?? require?'Config.php';???? require?'Model.php';???? class?User?extends?Model???? {???? ????protected?$dbnamePrefix?=?'cloude';???? ????protected?$tablePrefix?=?'user';???? }??? ?? function?create_uuid($prefix?=?""){?????? ????$str?=?md5(uniqid(mt_rand(),?true));????? ????$uuid??=?substr($str,0,8)?.?'-';????? ????$uuid?.=?substr($str,8,4)?.?'-';????? ????$uuid?.=?substr($str,12,4)?.?'-';????? ????$uuid?.=?substr($str,16,4)?.?'-';????? ????$uuid?.=?substr($str,20,12);????? ????return?$prefix?.?$uuid;?? }?? ?? $userId=create_uuid();?? $user?=?new?User($userId);?? $data=array('id'=>$userId,'name'=>'大明'.$userId,'password'=>'14e1b600b1fd579f47433b88e8d85291','sex'=>'男');???? if($result=$user->insert($data)){?? ????echo?'插入成功:','<pre/>';?? ????print_r($result);?? }?? ?? $condition=array("id"=>$userId);?? $list=$user->select($condition);?? if($list){?? ????echo?'查詢成功:','<pre/>';?? ????print_r($list);?? }??
6、結果 插入成功會返回插入到哪個庫哪個表,查詢成功返回從哪個庫哪個表查的
分庫分表注意事項: 1、維度問題 假如用戶購買了商品,需 要將交易記錄保存取來,如果按照用戶的緯度分表,則每個用戶的交易記錄都保存在同一表中,所以很快很方便的查找到某用戶的購買情況,但是某商品被購買的情 況則很有可能分布在多張表中,查找起來比較麻煩。反之,按照商品維度分表,可以很方便的查找到此商品的購買情況,但要查找到買人的交易記錄比較麻煩。 所以常見的解決方式有: 通過掃表的方式解決,此方法基本不可能,效率太低了。 記錄兩份數(shù)據(jù),一份按照用戶緯度分表,一份按照商品維度分表。 通過搜索引擎解決,但如果實時性要求很高,又得關系到實時搜索 2、避免分表join操作 因為關聯(lián)的表有可能不在同一數(shù)據(jù)庫中 3、避免跨庫事務 避免在一個事務中修改db0中的表的時候同時修改db1中的表,一個是操作起來更復雜,效率也會有一定影響 4、分表宜多不宜少;這樣做主要是為了盡量避免后期可能遇到的二次拆分 5、盡量把同一組數(shù)據(jù)放到同一DB服務器上 例如將賣家a的商品和交易信息都放到db0中,當db1掛了的時候,賣家a相關的東西可以正常使用。也就是說避免數(shù)據(jù)庫中的數(shù)據(jù)依賴另一數(shù)據(jù)庫中的數(shù)據(jù)
文章來源http://blog.csdn.NET/nuli888/article/details/52143065
來源:http://blog.csdn.net/weixin_29778143/article/details/72236453
與50位技術專家面對面20年技術見證,附贈技術全景圖
總結
以上是生活随笔為你收集整理的mysql分库分表实战及php代码操作完整实例的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。