亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

關于php處理Mysql特大數據表的解決方案

關于php處理Mysql特大數據表的解決方案

PHP
嗶嗶one 2019-03-12 18:12:25
1.目前有一張商品表,由于商品表數據超過250W 條,而且根據需求還會繼續激增,所以考慮進行分表設計。2.由于分表采用主鍵字段哈希分表,故需要將現有的250W 條數據進行hash處理分別插入到分出的10張表中,但是由于數據量太大,使用foreach來進行批量插入的時候每次都會超時。3.哪位大神有使用Php處理大數據的經驗,這種情況應該怎么處理。以下是我處理的代碼: for($i=0;$i<250;$i++){ $offset = $i*10000; $where = array('where' => ' id>0', 'limit' => '10000', 'offset'=>$offset, 'fields'=>['goods_id','goods_name','goods_price']); $res = $goodsModel->select($where ); foreach($res as $val){ //根據主鍵id進行hash獲取表名 $tab_name = 'goods_'. getStringHash($val['goods_id']); $data[$tab_name][] = $val; } foreach($data as $key=>$val){ $sql = "insert into {$key} "; $sql_val_str = ''; foreach($val as $v){ $sql_key = array_keys($v); $sql_val = array_values($v); $sql_val_str .= '('; foreach ($sql_val as $item) { $sql_val_str .= "'".$item."'"; $sql_val_str .= ','; } $sql_val_str = substr($sql_val_str, 0, -1); $sql_val_str .='),'; } $sql_key_str = '('.implode(',',$sql_key).')'; $sql_val_str = substr($sql_val_str, 0, -1); $sql .= $sql_key_str . 'values' . $sql_val_str; $goodsModel->exec_sql($sql); } } goods :id 商品碼 商品編號 商品價格 1 H235KHAK 123456 123465 主要結構就是這樣的,其中商品碼是不允許重復的,而且是10位數字和字母結合的隨意字符 分表后是根據商品碼進行hash計算,獲取hash值(0-9) 最后實現的結果是:goods_0,goods_1,goods_2....goods_9 將數據分布插入到這些表中 hash算法是在網上找的一個: function getStringHash($string, $tab_count=10) {/*{{{*/ $unsign = sprintf('%u', crc32($string)); if ($unsign > 2147483647) // sprintf u for 64 & 32 bit { $unsign -= 4294967296; } return abs($unsign) % $tab_count; }
查看完整描述

11 回答

?
精慕HU

TA貢獻1845條經驗 獲得超8個贊

因為代碼里面$data數組隨著循環次數增加,保存了庫中所有的記錄,

所以這不是set_time_limit和memory_limit太小的問題,需要優化代碼,

可以在第二個foreach后面增加unset($data)釋放內存。

然后這個查詢子句limit的offset會隨著循環次數增加,變得很大,后面的SQL查詢肯定會很慢,

如果主鍵id是連續的,可以考慮使用where id in (....)來獲取數據。

每次返回10000條記錄占用內存也很大,$goodsModel可以使用yield來降低內存使用。

另外,還有更簡單的 分表方式,直接在數據庫中寫SQL就行。

CREATE TABLE goods_1
CREATE TABLE goods_2
...
CREATE TABLE goods_10
..
INSERT INTO goods_1 SELECT * FROM goods WHERE id MOD 250000 = 0
INSERT INTO goods_2 SELECT * FROM goods WHERE id MOD 250000 = 1
...
INSERT INTO goods_10 SELECT * FROM goods  WHERE id MOD 250000  = 9

分表以后之前的代碼也許都需要改,這點也是需要考慮的,如果改代碼代價很大,可以實施分區(PARTITION)策略。

查看完整回答
1 反對 回復 2019-03-18
?
九州編程

TA貢獻1785條經驗 獲得超4個贊

你這個其實直接用mysql來做可能要快太多,你這個用的hash處理的,你直接可以

Insert into Table2(field1,field2,...) select value1,value2,... from Table1

后續按照你hash的加個條件。簡直不要太快。


以下為答案補充

其實,我這里不是很清楚你這個hash是怎么樣的一個算法,但是,我就假設你現在是基于這個商品ID來處理數據的;
那么假設你的,如果是自定義的hash的話,就還需要使用mysql的存儲過程了。
以下我以一個測試表倆舉例子

CREATE TABLE `test` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `value` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;
# 以上test表假設是原表,然后新創建0~9十個表,那么以下10條sql可以直接把原表數據快速拆分放到新的10個表
INSERT INTO test_0(value) SELECT `value` FROM test WHERE id % 10 = 0;
INSERT INTO test_1(value) SELECT `value` FROM test WHERE id % 10 = 1;
INSERT INTO test_2(value) SELECT `value` FROM test WHERE id % 10 = 2;
INSERT INTO test_3(value) SELECT `value` FROM test WHERE id % 10 = 3;
INSERT INTO test_4(value) SELECT `value` FROM test WHERE id % 10 = 4;
INSERT INTO test_5(value) SELECT `value` FROM test WHERE id % 10 = 5;
INSERT INTO test_6(value) SELECT `value` FROM test WHERE id % 10 = 6;
INSERT INTO test_7(value) SELECT `value` FROM test WHERE id % 10 = 7;
INSERT INTO test_8(value) SELECT `value` FROM test WHERE id % 10 = 8;
INSERT INTO test_9(value) SELECT `value` FROM test WHERE id % 10 = 9;

我好像沒看到你的hash是怎么實現的,如果知道的話,我也可以做個測試的來模擬,如果是hash商品編碼的話,需要用到存儲過程,相對來說又會復雜了一些。

查看完整回答
1 反對 回復 2019-03-18
?
拉莫斯之舞

TA貢獻1820條經驗 獲得超10個贊

有過類似經驗,你可以了解一下 swoole 異步任務,你250萬的數據,根據ID區間來劃分,開啟25個task進程,投遞25個task任務,每個進程也才10W的數據,非??炀湍軋绦型瓿?并且在cli命令行環境也不存在超時的問題。

查看完整回答
反對 回復 2019-03-18
?
猛跑小豬

TA貢獻1858條經驗 獲得超8個贊

我的想法是新產生的數據就按你分庫分表規則處理,已有數據能不動就不動了。如果已產生的數據一定要拆分,對PHP單獨處理數據而言這個數據量太大了,用PHP做多層嵌套循環,效率低,易超時。。??茨懿荒芸紤]用python來實現數據處理。個人想法,不足之處請諒解。

查看完整回答
反對 回復 2019-03-18
  • 11 回答
  • 0 關注
  • 544 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號