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 的功能,如果您重复调用类似的查询,则可以让数据库更有效地缓存查询。

其次,查询本身。是的,这些绝对可以简化。循环中的三个查询可以使用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

您应该从此查询中获得与要获取的三个记录相同的三个值。

你可以做的还有很多,但这是一个好的开始。我相信你会得到其他答案来进一步帮助你。

希望有帮助。

于 2013-03-25T22:28:27.210 回答
1

好的,正如其他人所说,使用 PDO/MYSQLI。但是,使用您已经拥有的代码,这里有两种方法可能会更好地工作和执行。

首先是使用相关子查询来获取负/正/中性值。这很好,因为它很短,但它绝不是理想的。您仍在对数据库执行大量查询(每个 uid + 初始更新 3 个)。但是,您只是从 php 向服务器发送一个查询,并让数据库完成所有其余工作。这可能对少数用户来说效果很好,但过一段时间就会开始出现性能问题。这一查询将更新 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());

从长远来看,第二个可能更好。在一次查询中查询出所有需要的数据。循环遍历该结果,将其格式化为 php,遍历该结果并进行更新。这个可能会执行得更好,因为您运行的查询数量要少得多(1 用于获取数据 + 1 用于每个 uid)。

//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

我会运行三个查询来获取您需要的信息:

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 对齐时递增行。返回结果的一个棘手之处是缺少 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 Fiddle上玩这个

于 2013-03-25T23:47:56.867 回答
-1

first try change your Mysql for mysqli

just change your db.php for:

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

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

And change your code for:

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";

That will onlye make one batch connection to the DB, and will print all the data in an array.

于 2013-03-25T22:18:11.700 回答