ここに mysql と php に関連する奇妙なバグがあります。私たちのサーバーにとってもパフォーマンスの問題である可能性があるのではないかと思っています.
リベート プロモーション コードの管理に使用するクラスを取得しました。コードは素晴らしく、正常に動作し、本来の目的を正確に実行します。saveChanges() 操作は、オブジェクトの状態に応じて INSERT または UPDATE を送信し、現在のコンテキストでは、クーポン コードを生成しようとしている原因のみを挿入します。
クラスの saveChanges は次のようになります: (古い mysql を使用するべきではないことはわかっていますが、ソフトウェアのアーキテクチャ上の制限により選択の余地がないため、その部分について文句を言わないでください)
public function saveChanges($asNew = false){
//Get the connection
global $conn_panier;
//Check if the rebate still exists
if($this->isNew() || $asNew){
//Check unicity if new
if(reset(mysql_fetch_assoc(mysql_query('SELECT COUNT(*) FROM panier_rabais_codes WHERE code_coupon = "'.mysql_real_escape_string($this->getCouponCode(), $conn_panier).'"', $conn_panier))) > 0){
throw new Activis_Catalog_Models_Exceptions_ValidationException('Coupon code "'.$this->getCouponCode().'" already exists in the system', $this, __METHOD__, $this->getCouponCode());
}
//Update the existing rebate
mysql_query($q = 'INSERT INTO panier_rabais_codes
(
`no_rabais`,
`code_coupon`,
`utilisation`,
`date_verrou`
)VALUES(
'.$this->getRebate()->getId().',
"'.mysql_real_escape_string(stripslashes($this->getCouponCode()), $conn_panier).'",
'.$this->getCodeUsage().',
"'.($this->getInvalidityDate() === NULL ? '0000-00-00 00:00:00' : date('Y-m-d G:i:s', strtotime($this->getInvalidityDate()))).'"
)', $conn_panier);
return (mysql_affected_rows($conn_panier) >= 1);
}else{
//Update the existing rebate
mysql_query('UPDATE panier_rabais_codes
SET
`utilisation` = '.$this->getCodeUsage().',
`date_verrou` = "'.($this->getInvalidityDate() === NULL ? '0000-00-00 00:00:00' : date('Y-m-d G:i:s', strtotime($this->getInvalidityDate()))).'"
WHERE
no_rabais = '.$this->getRebate()->getId().' AND code_coupon = "'.mysql_real_escape_string($this->getCouponCode(), $conn_panier).'"', $conn_panier);
return (mysql_affected_rows($conn_panier) >= 0);
}
}
ご覧のとおり、コード自体は非常に単純でクリーンで、挿入が成功した場合は true を返し、失敗した場合は false を返します。
コードの他の部分では、次のようにランダム アルゴリズムを使用してコードを生成します。
while($codes_to_generate > 0){
//Sleep to delay mysql choking on the input
usleep(100);
//Generate a random code
$code = strtoupper('RC'.$rebate->getId().rand(254852, 975124));
$code .= strtoupper(substr(md5($code), 0, 1));
$rebateCode = new Activis_Catalog_Models_RebateCode($rebate);
$rebateCode->setCouponCode($code);
$rebateCode->setCodeUsage($_REQUEST['utilisation_generer']);
try{
if($rebateCode->saveChanges()){
$codes_to_generate--;
$generated_codes[] = $code;
}
}catch(Exception $ex){
}
}
ここでわかるように、注意すべき点が 2 つあります。生成するコードの数と生成されたコードの配列は、saveChanges から true が返された場合にのみ満たされるため、mysql は、この部分が発生するために情報が挿入されたことを報告する必要があります。
もう 1 つのヒントは、while の最初の行です。
//Sleep to delay mysql choking on the input
usleep(100);
え?さて、この投稿はこれについてすべてです。私のコードは、生成する少量のコードで問題なく動作します。しかし、一度に複数のコードを保存するように mysql に依頼した場合、usleep を使用して自分自身を調整する必要があります。そうしないと、mysql がこれらの行の一部を削除します。影響を受ける行があるが保存されていないことが報告されます。
100 行以下ではスロットリングは必要なく、挿入する行数に応じてスリープする必要があります。それは単純なものでなければなりませんが、私にはわかりません。これは、私が挿入しようとした行と、実装しなければならなかった最小の usleep スロットルの合計です。
- < 100 行: なし
- < 300 ライン: 2 ミリ秒
- < 1000 行: 5 ミリ秒
- < 2000 行: 10 ミリ秒
- < 5000 行: 20 ミリ秒
- < 10000 行: 100 ミリ秒
お時間をいただきありがとうございます