日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

mysql分库分表实战及php代码操作完整实例

發布時間:2024/9/20 数据库 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mysql分库分表实战及php代码操作完整实例 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

當單表達到幾千萬時,查詢一次要很久,如果有聯合查詢,有可能會死在那
分庫分表主要就是解決這個問題,減小數據庫的負擔,縮短查詢時間

分庫:
1)按功能分
用戶類庫、商品類庫、訂單類庫、日志類、統計類庫...
1)按地區分
每個城市或省市一個同樣的庫,加上后綴或前綴如:db_click_bj、db_click_sh...

分表:
1、橫向分表 解決表記錄太大問題
1)按某個字段分,
如:discuz的附件表分成10個附件分表pre_forum_attachment_0到pre_forum_attachment_9,還有1個附件索引表pre_forum_attachment存儲tid和附件id關系
根據主題的tid最后一位來決定附件要保存在哪個分表,
2)按日期分表
一些日志、統計類的可以按年、月、日、周分表
如:點擊量統計click_201601、click_201602
3)使用mysql的merge
先把分表創建好,然后創建總表指定engine= MERGE UNION=(table1,table2) INSERT_METHOD = LAST;

2、縱向分表 解決列過多問題
1)經常組合查詢的列放在一個表,常用字段的表可考慮Memory引擎
2)不經常使用的字段單獨成表
3)把text、blob等大字段拆分放在附表
如:phpcms的文章表分成主表v9_news和從表v9_news_data,主表存標題、關鍵字、瀏覽量等,從表存具體內容、模板等

很多主流mvc框架都提供了切換數據庫訪問方法

thinkphp切換數據庫

$this->db(1,"mysql://root:123456@localhost:3306/test")->query("查詢sql");//數據庫連接信息可放在配置文件
$this->db(1)->query("查詢sql");//下次直接使用編號1定位

分表的話 在查詢前先根據分表規則把表名查出


這里用兩臺機子簡單以同個業務庫分庫,同個表分表,演示插入、查詢如何定位庫和表并最終成功執行

兩臺機子:

server1:192.168.1.198

server2:192.168.1.199

兩臺機子都執行下面操作


1、先創建10個數據庫,每個數據庫10個表

當然也可以改成百庫百表,也可手動創建,我為了方便寫了個腳本批量創建

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++){//10個庫??
  • ????????$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++){????????//10個表??
  • ????????????????$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){??
  • ????????????????????//echo?"create?table?user_{$j}?successful!?<br/>";??
  • ????????????????}else{??
  • ????????????????????//echo?"create?error!";??
  • ????????????????}??
  • ????????????}??
  • ????????}??
  • ????}??
  • }else{??
  • ????echo?"connect?error!!!!";??
  • }??

  • 2、分庫分表路由實現

    Config.PHP

    [php]?view plaincopy
  • <?php??
  • class?Config{????
  • ????public?$dsn;????
  • ????public?$user;????
  • ????public?$password;????
  • ????public?$dbname;?//分庫分表后得到的數據庫名??
  • ????public?$table;?//分庫分表后得到的表名??
  • ????private?static?$config;//mysql配置數組??
  • ????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、數據庫配置文件
    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?的庫使用的鏈接配置??
  • ?????????????????*/???
  • ????????????????'0-4'?=>?$default,????
  • ????????????????/**??
  • ?????????????????*?編號為?5?到?9?的庫使用的鏈接配置??
  • ?????????????????*/???
  • ????????????????'5-9'?=>?$db_199,?????
  • ??????
  • ????????????),????
  • ??????
  • ????????????//?分庫分表規則????
  • ????????????/**??
  • ?????????????*?下面的配置對應10庫10表?
  • ?????????????*?如果根據?uid?進行分表,假設?uid?為?224,對應的庫表為:??
  • ?????????????*??(224?/?1)?%?10?=?4?為編號為?4?的庫??
  • ?????????????*??(224?/?10)?%?10?=?1?為編號為?2?的表??
  • ?????????????*/???
  • ????????????'database_split'?=>?array(1,?10),????
  • ????????????'table_split'?=>?array(10,?10),????
  • ????????),????
  • ????),????
  • );????
  • return?$config;??

  • 4、模型類操作數據庫

    Model.PHP

    [php]?view plaincopy
  • <?php??
  • require_once?'Config.php';//引入配置信息??
  • class?Model{????
  • ????public?$config;?????//數據庫配置??
  • ????public?$connection;?//pdo??
  • ????protected?$dbnamePrefix;?//庫前綴如cloude_50?前綴為cloude???
  • ????protected?$tablePrefix;??//表前綴??
  • ????protected?$dbname;??//分庫分表后對應的庫??
  • ????protected?$table;???//分庫分表后對應的庫表??
  • ??????
  • ????public?function?__construct($id){????
  • ????????$this->config?=?new?Config($this->dbnamePrefix,?$this->tablePrefix,?$id);??????????????????//根據id找到對應庫和表??
  • ????????$this->connection?=?new?Pdo($this->config->dsn,?$this->config->user,?$this->config->password);//實例化pdo????
  • ????????$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)?{??
  • ????????????//構建插入多條數據的sql語句??
  • ????????????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?{??
  • ????????????//構建插入單條數據的sql語句??
  • ????????????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';????
  • }???
  • //生成唯一uuid??
  • 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、維度問題
    假如用戶購買了商品,需 要將交易記錄保存取來,如果按照用戶的緯度分表,則每個用戶的交易記錄都保存在同一表中,所以很快很方便的查找到某用戶的購買情況,但是某商品被購買的情 況則很有可能分布在多張表中,查找起來比較麻煩。反之,按照商品維度分表,可以很方便的查找到此商品的購買情況,但要查找到買人的交易記錄比較麻煩。
    所以常見的解決方式有:
    通過掃表的方式解決,此方法基本不可能,效率太低了。
    記錄兩份數據,一份按照用戶緯度分表,一份按照商品維度分表。
    通過搜索引擎解決,但如果實時性要求很高,又得關系到實時搜索
    2、避免分表join操作 因為關聯的表有可能不在同一數據庫中
    3、避免跨庫事務
    避免在一個事務中修改db0中的表的時候同時修改db1中的表,一個是操作起來更復雜,效率也會有一定影響
    4、分表宜多不宜少;這樣做主要是為了盡量避免后期可能遇到的二次拆分
    5、盡量把同一組數據放到同一DB服務器上

    例如將賣家a的商品和交易信息都放到db0中,當db1掛了的時候,賣家a相關的東西可以正常使用。也就是說避免數據庫中的數據依賴另一數據庫中的數據


    文章來源http://blog.csdn.NET/nuli888/article/details/52143065


    來源:http://blog.csdn.net/weixin_29778143/article/details/72236453

    與50位技術專家面對面20年技術見證,附贈技術全景圖

    總結

    以上是生活随笔為你收集整理的mysql分库分表实战及php代码操作完整实例的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。