如何使用日期范围优化这些查询?

时间:2015-02-24 21:35:22

标签: php mysql

我有一个带有权重日志的表,其中包含这些字段(以及其他字段)和示例数据:

userid  date        weight
---------------------------
1       2015-01-10  100
1       2015-01-15  90
1       2015-01-20  80
2       2015-01-05  120
2       2015-01-15  110
3       2015-01-15  150
3       2015-01-24  140

我需要在日期之间减掉总重量。目前,在 2015-01-09 2015-01-21 之间,我在PHP中使用此功能:

function get_weight_loss($userid, $start_date, $end_date) {
    global $db;
    $query = "
        SELECT date, weight FROM weight_tracker_log 
            WHERE date=(
                SELECT MAX(date) FROM weight_tracker_log 
                    WHERE date <= '$start_date' AND userid = $userid 
            ) AND userid = $userid 
    ";
    $result = mysql_query($query, $db);
    $previous = mysql_fetch_assoc($result);
    if ( !$previous['date'] ) {
        /* Get first entry for user */
        $query = "
            SELECT date, weight FROM weight_tracker_log 
                WHERE date=(
                    SELECT MIN(date) FROM weight_tracker_log 
                        WHERE userid = $userid 
                ) AND userid = $userid 
        ";
        $result = mysql_query($query, $db);
        $previous = mysql_fetch_assoc($result);
    };
    $query = "
        SELECT date, weight FROM weight_tracker_log 
            WHERE date=(
                SELECT MAX(date) FROM weight_tracker_log 
                    WHERE date <= '$end_date' AND userid = $userid 
            ) AND userid = $userid 
    ";
    $result = mysql_query($query, $db);
    $next = mysql_fetch_assoc($result);
    mysql_free_result($result);
    if ( $previous['date'] && $next['date'] && $previous['date']<$next['date'] && $next['date']>$start_date) {
        return $previous['weight'] - $next['weight'];
    } else {
        return 0;
    };
};

它工作正常,但计算越来越长。它的作用是:

  1. $start_date
  2. 之前查找用户的最新条目
  3. 如果不存在:在 $start_date
  4. 之后查找第一个用户的条目
  5. 在范围内寻找最后一个条目(并获得重量)
  6. 如果第一个日期小于秒,则计算重量差
  7. 有没有办法优化查询或算法本身?

    该表是以这种方式创建的:

    CREATE TABLE `weight_tracker_log` (
     `id` int(11) NOT NULL AUTO_INCREMENT,
     `userid` int(11) NOT NULL COMMENT 'xcart_cutomers',
     `weight` int(11) NOT NULL COMMENT 'grams',
     `date` date NOT NULL COMMENT 'YYYY-MM-DD',
     `is_start_weight` char(1) NOT NULL DEFAULT 'N',
     `is_end_weight` char(1) NOT NULL DEFAULT 'N',
     `image` varchar(255) NOT NULL,
     PRIMARY KEY (`id`)
    ) ENGINE=MyISAM AUTO_INCREMENT=97526 DEFAULT CHARSET=utf8
    

1 个答案:

答案 0 :(得分:3)

我没有在你的桌子上看到任何索引。这意味着每个SELECT必须遍历整个表以查找受影响的行。想象一下,如果你不得不翻阅500页书的每一页,只是为了找到与狗有关的两页。

您需要在dateuserid列添加索引:

CREATE INDEX weight_tracker_log_date ON weight_tracker_log ( date );
CREATE INDEX weight_tracker_log_userid ON weight_tracker_log ( userid );

http://use-the-index-luke.com/是对如何以及为何使用索引的精彩介绍。