0

このスクリプトを毎日(cron)実行して、1か月のフィードバックの合計量を更新する必要があります(少なくとも、これは私が今考案したものです)。これが私が持っているコードです。誰かが私がこれについてどうやって得るべきかについてより良い考えを持っていますか?たぶん、これについてのやり方を変えたり、updateMonthlyFeedback.phpスクリプトを最適化したりしますか?

updateMonthlyFeedback.php

session_start();
include("db.php");

$sql="SELECT MAX(uid) as maxUID FROM users";
$result = mysql_query($sql) or die(mysql_error());
$row = mysql_fetch_array($result);
$maxUID = $row['maxUID'];

for($i=0;$i<$maxUID;$i++){
    $sql="SELECT COUNT(*) as negativeCount FROM feedbacks WHERE date_created >= ( CURDATE() - INTERVAL 30 DAY ) AND type = -1 AND uid = '$i'";
    $result = mysql_query($sql) or die(mysql_error());
    $row = mysql_fetch_array($result);
    $negativeCount = $row['negativeCount'];
    $sql="SELECT COUNT(*) as neutralCount FROM feedbacks WHERE date_created >= ( CURDATE() - INTERVAL 30 DAY ) AND type = 0 AND uid = '$i'";
    $result = mysql_query($sql) or die(mysql_error());
    $row = mysql_fetch_array($result);
    $neutralCount = $row['neutralCount'];
    $sql="SELECT COUNT(*) as positiveCount FROM feedbacks WHERE date_created >= ( CURDATE() - INTERVAL 30 DAY ) AND type = 1 AND uid = '$i'";
    $result = mysql_query($sql) or die(mysql_error());
    $row = mysql_fetch_array($result);
    $positiveCount = $row['positiveCount'];
    $sql = "UPDATE feedback_totals SET negativeCount = '$negativeCount', neutralCount = '$neutralCount', positiveCount = '$positiveCount' WHERE uid = '$i'";
    $result=mysql_query($sql) or die(mysql_error());
}

MySQLテーブル

CREATE TABLE feedback_totals (
    uid                     VARCHAR(40),
    negativeCount           int,
    neutralCount            int,                
    positiveCount           int,
    halfStarCount           int,
    oneStarCount            int,
    oneHalfStarCount        int,
    twoStarCount            int,
    twoHalfStarCount        int,
    threeStarCount          int,
    threeHalfStarCount      int,
    fourStarCount           int,
    fourHalfStarCount       int,
    fiveStarCount           int,
    PRIMARY KEY             (uid)
    #FOREIGN KEY            (uid) REFERENCES users(uid) ON DELETE CASCADE
);

CREATE TABLE feedback_last_month (
    uid                     VARCHAR(40),
    negativeCount           int,
    neutralCount            int,                
    positiveCount           int,
    halfStarCount           int,
    oneStarCount            int,
    oneHalfStarCount        int,
    twoStarCount            int,
    twoHalfStarCount        int,
    threeStarCount          int,
    threeHalfStarCount      int,
    fourStarCount           int,
    fourHalfStarCount       int,
    fiveStarCount           int,
    PRIMARY KEY             (uid)
    #FOREIGN KEY            (uid) REFERENCES users(uid) ON DELETE CASCADE
);

CREATE TABLE feedback (
    feedback_id             INT NOT NULL AUTO_INCREMENT,
    uid                     VARCHAR(40),INDEX (uid),
    sender_id               VARCHAR(40),
    type                    int,                #-1 = neg, 0 = neutral, 1 = positive
    starCount               VARCHAR(40),
    description             VARCHAR(80),
    date_created            timestamp DEFAULT CURRENT_TIMESTAMP, 
    fromType                VARCHAR(40), # buyer or seller
    fromUsername            VARCHAR(40),
    PRIMARY KEY             (feedback_id)
    #FOREIGN KEY            (uid) REFERENCES users(uid) ON DELETE CASCADE
);
4

5 に答える 5

1

ここでは明らかにかなりの繰り返しが行われています。そのほとんどはコードをリファクタリングすることで削除できますが、現在のプロセスでも開始点として、より優れたデータベースAPIを使用することでパフォーマンスを向上させることができます。

したがって、最初にお勧めするのは、関数の使用を停止し、代わりにライブラリmysql_xxx()の使用に切り替えることです。PDO古いmysql関数はとにかく非推奨になっているため、可能な限り使用することはお勧めしませんが、この場合PDO、古い関数に比べてパフォーマンスが大幅に向上するため、代わりに使用する特別な理由があります。

PDOを使用すると、Prepared Queriesと呼ばれる機能を使用できるため、同様のクエリを繰り返し呼び出す場合に、データベースでクエリをより効率的にキャッシュできます。

第二に、クエリ自体。はい、これらは間違いなく単純化できます。ループ内の3つのクエリは、を使用して1つのクエリに組み合わせることができますGROUP BY。クエリは次のようになります。

SELECT COUNT(*) FROM users
WHERE date_created >= ( CURDATE() - INTERVAL 30 DAY )
AND uid = :uid
AND type = -1 OR type = 1 OR type = 1
GROUP BY type

このクエリから、フェッチする3つのレコードと同じ3つの値を取得する必要があります。

できることはまだまだたくさんありますが、それは良いスタートです。私はあなたがさらにあなたを助けるために他の答えを得ると確信しています。

お役に立てば幸いです。

于 2013-03-25T22:28:27.210 に答える
1

OK、他のみんなが言ったように、PDO/MYSQLIを使用してください。ただし、すでにお持ちのコードを使用すると、次の2つの方法が機能し、パフォーマンスが向上する可能性があります。

1つは、相関サブクエリを使用して、負/正/中立の値を取得することです。これは短いのでいいのですが、決して理想的ではありません。あなたはまだデータベースに対して大量のクエリを実行しています(各uidに3つ+初期更新)。ただし、phpからサーバーに送信するクエリは1つだけで、残りのすべての作業はデータベースに任せています。これは、一部のユーザーにとっては問題なく機能する可能性がありますが、しばらくするとパフォーマンスの問題が発生し始めます。この1つのクエリは、feedback_totalsのすべての行を更新します。ただし、feedback_totalsに行がない場合、新しいuidの新しい行は挿入されません。

//one query, this is it. updates it all.
$sql = "UPDATE `feedback_totals`
        SET
            `negativeCount`=(SELECT COUNT(*) FROM `users` WHERE `uid`=`feedback_totals`.`uid` AND `date_created` >= (CURDATE() - INTERVAL 30 DAY) AND `type`=-1),
            `positiveCount`=(SELECT COUNT(*) FROM `users` WHERE `uid`=`feedback_totals`.`uid` AND `date_created` >= (CURDATE() - INTERVAL 30 DAY) AND `type`=1),
            `neutralCount`=(SELECT COUNT(*) FROM `users` WHERE `uid`=`feedback_totals`.`uid` AND `date_created` >= (CURDATE() - INTERVAL 30 DAY) AND `type`=0)";
$result=mysql_query($sql) or die(mysql_error());

長期的には2番目の方がおそらく良いでしょう。1つのクエリで必要なすべてのデータをクエリします。その結果をループしてphpでフォーマットし、ループして更新を行います。実行するクエリの数がはるかに少ないため(データを取得するために1 +各uidに1)、これはおそらくパフォーマンスが向上します。

//query for all the data
$sql="SELECT
            `uid`,
            `type`,
            COUNT(*) AS cnt
        FROM `users`
        WHERE `date_created` >= (CURDATE() - INTERVAL 30 DAY)
        GROUP BY `uid`,`type`";
$result=mysql_query($sql) or die(mysql_error());

$data = array();
//loop through the result
while($row=mysql_fetch_assoc($result)){
    //if the uid is not in $data
    if(!isset($data[$row['uid']])){
        //add it with a blank array
        $data[$row['uid']] = array('negativeCount'=>0,'neutralCount'=>0,'positiveCount'=>0);
    }
    //add to the data for this uid depending on type
    if($row['type']==-1){
        $data[$row['uid']]['negativeCount']=$row['cnt'];
    } elseif($row['type']==1){
        $data[$row['uid']]['positiveCount']=$row['cnt'];
    } else {
        $data[$row['uid']]['neutralCount']=$row['cnt'];
    }
}

//now loop through the data and update the table
foreach($data as $uid=>$cnt){
    $sql = "UPDATE `feedback_totals`
            SET
                `negativeCount`={$cnt['negativeCount']},
                `positiveCount`={$cnt['positiveCount']},
                `neutralCount`={$cnt['neutralCount']}
            WHERE `uid`=$uid";
    $result=mysql_query($sql) or die(mysql_error());
}
于 2013-03-25T22:36:08.093 に答える
0

必要な情報を取得するために3つのクエリを実行します。

SELECT uid, COUNT(*) as negativeCount FROM users
WHERE date_created >= ( CURDATE() - INTERVAL 30 DAY ) AND type = -1 
GROUP BY uid ORDER BY uid ASC";

SELECT uid, COUNT(*) as neutralCount FROM users
WHERE date_created >= ( CURDATE() - INTERVAL 30 DAY ) AND type = 0
GROUP BY uid ORDER BY uid ASC";

SELECT uid, COUNT(*) as positiveCount FROM users
WHERE date_created >= ( CURDATE() - INTERVAL 30 DAY ) AND type = 1 
GROUP BY uid ORDER BY uid ASC";

次に、結果をウォークし、現在のuidと一致するように行をインクリメントします。返される結果の1つのトリッキーな点は、uidがない場合はカウントが0であることを示します。ただし、それらは順序付けられているため、返される結果(使用しているfetch_rowを介して)またはそれぞれの個別のインデックスをインクリメントする必要があります。結果の。

次のようになります。

// Have to load up the first result
$p_row = mysql_fetch_array($positive_result);
$neu_row = mysql_fetch_array($neutral_result);
$neg_row = mysql_fetch_array($negative_result);

for($i = 0; $i < $maxUID; $i++){
  $positive = $neutral = $negative = 0;
  if($p_row[0] == $i){
    $positive = $p_row[1];
    $p_row = mysql_fetch_array($positive_result);
  }
  if($neu_row[0] == $i){
    $neutral = $neu_row[1];
    $neu_row = mysql_fetch_array($neutral_result);
  }
  if($neg_row[0] == $i){
    $negative = $neg_row[1];
    $neg_row = mysql_fetch_array($negative_result);
  }
  $sql = "UPDATE feedback_totals SET negativeCount = '$negative', neutralCount = '$neutral', positiveCount = '$positive' WHERE uid = '$i'";
  mysql_query($sql) or die(mysql_error());
}
于 2013-03-25T22:47:53.877 に答える
0

これはすべて、単一のSQLクエリで実行できます。

INSERT INTO `feedback_totals` (uid,negativeCount,positiveCount,neutralcount)
SELECT users.uid, 
  COUNT(neg.feedback_id) as negativeCount, 
  COUNT(pos.feedback_id) as positiveCount, 
  COUNT(neut.feedback_id) AS neutralCount
FROM users
LEFT JOIN feedback neg  ON neg.uid =users.uid AND neg.type=-1 AND neg.date_created >=(CURDATE() - INTERVAL 30 DAY)
LEFT JOIN feedback pos  ON pos.uid =users.uid AND pos.type=1  AND pos.date_created >=(CURDATE() - INTERVAL 30 DAY)
LEFT JOIN feedback neut ON neut.uid=users.uid AND neut.type=0 AND neut.date_created>=(CURDATE() - INTERVAL 30 DAY)
GROUP BY uid
ON DUPLICATE KEY UPDATE 
  negativeCount=VALUES(negativeCount), 
  positiveCount=VALUES(positiveCount), 
  neutralCount=VALUES(neutralCount);

これON DUPLICATE KEY UPDATEにより、クエリで新しい行を追加したり、既存の行を更新したりできます。SQLフィドルでこれで遊ぶことができます

于 2013-03-25T23:47:56.867 に答える
-1

まず、MySQLformysqliを変更してみてください

db.phpを次のように変更するだけです。

$mysqli = new mysqli("localhost", "XXX", "XXX", "XXX");

if ($mysqli->connect_errno) {
    printf("Connect failed: %s\n", $mysqli->connect_error);
    exit();
}

そして、次のコードを変更します。

session_start();
include("db.php");
$sql="SELECT MAX(uid) as maxUID FROM users; ";

for($i=0;$i<$maxUID;$i++){
    $sql.="SELECT COUNT(*) as negativeCount FROM users WHERE date_created >= ( CURDATE() - INTERVAL 30 DAY ) AND type = -1 AND uid = '$i'; ";
    $sql.="SELECT COUNT(*) as neutralCount FROM users WHERE date_created >= ( CURDATE() - INTERVAL 30 DAY ) AND type = 0 AND uid = '$i'; ";
    $sql.="SELECT COUNT(*) as positiveCount FROM users WHERE date_created >= ( CURDATE() - INTERVAL 30 DAY ) AND type = 1 AND uid = '$i'; ";
    $sql.="UPDATE feedback_totals SET negativeCount = '$negativeCount', neutralCount = '$neutralCount', positiveCount = '$positiveCount' WHERE uid = '$i'; ";
}   

if ($mysqli->multi_query($sql)) {
    do {
        $rows=array();
        if ($result = $mysqli->store_result()) {
            while($rows[] = mysqli_fetch_assoc($result));
            array_pop($rows); 
            $result->free();
        }
        $data[]=$rows;
    } while ($mysqli->next_result());
    print_r($data);
} else
    echo "Error with SQL";

これにより、DBへのバッチ接続が1回だけ行われ、すべてのデータが配列に出力されます。

于 2013-03-25T22:18:11.700 に答える