ホームページ >バックエンド開発 >PHPチュートリアル >MySQL の数千万のデータを最適化する方法
function insert(){ global $m; if (!isset($_REQUEST['strs']) || !isset($_REQUEST['type']) || !isset($_REQUEST['hash'])){ echo 'param error'; return; } //strs为所有字符串 $poststr = $_REQUEST['strs']; $xstrs = json_decode(stripslashes($poststr), true); $type = $_REQUEST['type']; $hash = $_REQUEST['hash']; if (count($xstrs) <= 0){ $msg = 'str error'; DsLog::errLog($msg.$poststr); echo $msg; return; } if ($type == '0'){ $table = 'white'; } else if($type == '1'){ $table = 'black'; } else{ $msg = 'type error'; DsLog::errLog($msg); echo $msg; return; } $strs = array(); for($i = 0; $i < count($xstrs); $i++) { $strtmp = $xstrs[$i]; $strtmp = trim($strtmp); $strtmp = strtolower($strtmp); $strtmp = addslashes($strtmp); if (strlen($strtmp) > 256){ $strtmp = substr($strtmp, 0, 256); } if (strlen($strtmp) >= 7) { array_push($strs, $strtmp); } } //拼接所有字符串 $tmp = '("'.implode('","', $strs).'")'; //获取已存在的字符串 $sql = "select * from $table where str in $tmp"; $ret = mysql_query($sql, $m); if (!$ret){ $msg = 'exec error:'.mysql_error($m).','.$sql; DsLog::errLog($msg); echo $msg; return; } $exists = array(); $notexists = array(); $count = mysql_num_rows($ret); for ($i = 0; $i < $count; $i++) { $item = mysql_fetch_assoc($ret); if (!$item){ break; } array_push($exists, $item['str']); } for ($i = 0; $i < count($strs); $i++){ if (in_array($strs[$i], $exists)){ continue; } array_push($notexists, $strs[$i]); } for($i = 0; $i < count($exists); $i++) { $exists[$i] = addslashes($exists[$i]); } for($i = 0; $i < count($notexists); $i++) { $notexists[$i] = addslashes($notexists[$i]); } if (count($exists) > 0){ //更新已存在字符串的count字段 $tmp = '("'.implode('","', $exists).'")'; $time = date('YmdHi'); $sql = "update $table set count=count+1 where str in $tmp"; $ret = mysql_query($sql, $m); if (!$ret){ $msg = 'exec error:'.mysql_error($m).','.$sql; DsLog::errLog($msg); echo $msg; return; } //更新已存在字符串的upd字段 $sql = "update $table set upd='$time' where str in $tmp"; $ret = mysql_query($sql, $m); if (!$ret){ $msg = 'exec error:'.mysql_error($m).','.$sql; DsLog::errLog($msg); echo $msg; return; } } //插入新信息 if (count($notexists) > 0){ $time = date('YmdHi'); $sql = "insert ignore into $table (str,hash,count, upd) values"; for ($i = 0; $i < count($notexists); $i++){ $str = $notexists[$i]; $crc = sprintf("%u", crc32($str)); $sql .= "('$str','$crc','1', '$time'),"; } $sql = substr($sql, 0, strlen($sql) - 1); $ret = mysql_query($sql, $m); if (!$ret){ $msg = 'insert error:'.mysql_error($m).','.$sql; DsLog::errLog($msg); echo $msg; return; } } echo !!$ret; }
返信ディスカッション(解決策)へ
ボトルネックがデータベース内のクエリと変更の3つのステートメントにあることを確認できますか?
毎回投稿される文字列の平均数は1500とのことですが 1500ワードということでしょうか?そうでない場合でも (文字列の長さです)、単語ごとの平均 20 文字に基づくと、まだ 75 単語あります
フィルター条件は str in $tmp (str in ('xxx','xxx'. ...)) つまり、テーブル内のレコードごとに 1500 (75) 回の文字列比較が必要で、ヒット率は最大 1/1500 (1/75) になると思いますか?
データベースの強みはレコード間の比較にありますが、実行しているのは列間の弱い比較です
受信データを使用して一時テーブル (行ごとに 1 ワード) を構築し、メイン テーブルで関連する操作を実行できます。この方法でのみデータベースを活用できます
また、2 つの連続する update ステートメントをマージすることはできませんか?
毎回投稿される文字列の平均数は1500とのことですが
1500ワードということでしょうか?そうでない場合でも (文字列の長さです)、単語ごとの平均 20 文字に基づくと、まだ 75 単語あります
フィルター条件は str in $tmp (str in ('xxx','xxx'. ...)) つまり、テーブル内のレコードごとに 1500 (75) 回の文字列比較が必要で、ヒット率は最大 1/1500 (1/75) になると思いますか?
データベースの強みはレコード間の比較にありますが、実行しているのは列間の弱い比較です
受信データを使用して一時テーブル (行ごとに 1 ワード) を構築し、メイン テーブルで関連する操作を実行できます。この方法でのみデータベースを活用できます
また、2 つの連続する update ステートメントをマージすることはできませんか?
1500ワードということでしょうか?そうでない場合でも (文字列の長さです)、単語ごとの平均 20 文字に基づくと、まだ 75 単語あります
フィルター条件は str in $tmp (str in ('xxx','xxx'. ...)) つまり、テーブル内のレコードごとに 1500 (75) 回の文字列比較が必要で、ヒット率は最大 1/1500 (1/75) になると思いますか?
データベースの強みはレコード間の比較にありますが、実行しているのは列間の弱い比較です
受信データを使用して一時テーブル (行ごとに 1 ワード) を構築し、メイン テーブルで関連する操作を実行できます。この方法でのみデータベースを活用できます
また、2 つの連続する update ステートメントをマージすることはできませんか?
id select_type table type possible_keys key key_len ref rows Extra1 SIMPLE tmp index str str 770 NULL 2531 Using index1 SIMPLE white eq_ref str str 770 bayes.tmp.str 1
id select_type table type possible_keys key key_len ref rows Extra1 SIMPLE white range str str 770 NULL 2531 Using where
mysql_error のようなライブラリ関数も非効率的です私が PHP を学習していたときは、PDO を直接起動したことはほとんどありませんでした。
また、 でキーワードを使用しましたが、インデックスされていないようです。
効果はほぼ同じだと感じます