4

我正在使用 MySQL 并有一个user_data这样的表:

user_id         int(10) unsigned
reg_date        int(10) unsigned
carrier         char(1)

reg_data 是注册时间的 unix 时间戳(可以是一天中的任何一秒),运营商是运营商的类型,其可能值只能是“D”、“A”或“V”。

我需要编写一个sql语句来选择从2013/01/01到2013/01/31的每一天不同运营商的注册用户数。所以理想的结果可能是:

2013/01/01   D   10
2013/01/01   A   31
2013/01/01   V   24
2013/01/02   D    9
2013/01/02   A   23
2013/01/02   V   14
....
2013/01/31   D   11
2013/01/31   A   34
2013/01/31   V   22

谁能帮我解决这个问题?我需要给出最好的答案,这意味着我可以在必要时添加索引,但我需要保持查询的效率。

目前,我在 (reg_date,carrier) 上创建了一个索引并使用以下查询:

select FROM_UNIXTIME(reg_date, "%M %D %Y") as reg_day, carrier, count(carrier) as user_count
from user_data
where reg_date >= UNIX_TIMESTAMP('2013-01-01 00:00:00') and reg_date < UNIX_TIMESTAMP('2013-02-01 00:00:00')
group by reg_day, carrier
order by reg_date;

谢谢!

4

1 回答 1

1

如果您无法更改表格(存储单个日期会有所帮助),则只能使用索引,然后:

创建一个复合索引:carrier, reg_date,然后按 分组carrier, reg_date和排序reg_date, carrier

您可以仅为时间戳创建其他索引(它可能更适合 WHERE 原因,具体取决于您在范围之外的记录数)。

此外,您可以使用完全 unix 时间戳,然后将其嵌入为子查询,外部可以将时间戳转换为人类可读的日期(这样转换是在组之后完成的,而不是针对每个单独的记录)。

创建索引:

CREATE INDEX bytime ON user_data (reg_date);
CREATE INDEX daily_group ON user_data (carrier, reg_date);

询问:

SELECT FROM_UNIXTIME(reg_day, "%M %D %Y") AS reg_day
    , carrier
    , user_count
FROM (
    SELECT FLOOR(reg_date / (60 * 60 * 24)) AS reg_day
        , carrier
        , count(carrier) AS user_count
    FROM user_data
    WHERE reg_date >= UNIX_TIMESTAMP('2013-01-01 00:00:00')
        AND reg_date < UNIX_TIMESTAMP('2013-02-01 00:00:00')
    GROUP BY carrier, reg_day
    ORDER BY reg_day, carrier
    ) AS a;
于 2013-03-25T09:21:42.677 回答