4

我有一个图片帖子的用户供稿。每个用户都可以发布单个图像,但是,他可以经常重复该动作。比如说,在一小时内上传几张图片。

我如何有效地设计数据库表,以便当用户在一小时内发布多张图片(一张一张)时——我可以轻松地将这些连续帖子组合在一起,例如在 INSERT 或 SELECT 上?


不建议多上传表单。事实并非如此:我刚刚用更常见的术语描述了这项任务:)

4

4 回答 4

3

您可以为每个帖子存储一个时间戳,然后从下一个中选择时间戳小于某个阈值的每个项目吗?

另一个想法是在每个帖子中存储时间戳和“组号”。在存储帖子之前,执行 a以查找在最后几分钟SELECT内提交的帖子。n如果您找到一个,请为新帖子使用相同的组号。如果您不这样做,则增加新帖子的组号。然后您可以按组号选择以找到您想要的项目。

于 2012-05-10T21:58:12.313 回答
2

我想数据模型看起来像这样:

在此处输入图像描述

只需注意确保帖子之间的时间差异大于 TIMESTAMP 的分辨率(或准备好优雅地处理 PK 违规)。

在支持分析功能的 DBMS 中,您可以相当轻松地将时间上接近的帖子分组。例如,Oracle 查询分组的帖子(对于给定的用户)在一个小时内,看起来像这样:

SELECT T.*, SUM(DIFF) OVER (ORDER BY TIMESTAMP) GROUPING
FROM (
    SELECT
        IMAGE.*,
        CASE
            WHEN TIMESTAMP <= LAG(TIMESTAMP) OVER (ORDER BY TIMESTAMP)
                + INTERVAL '1' HOUR
            THEN 0
            ELSE 1
            END DIFF
    FROM IMAGE
    WHERE USER_ID = :user_id
) T;

生成的 GROUPING 字段将识别 TIMESTAMP “足够接近”的各个行组。这个查询也非常有效——它只是对 PK 索引的范围扫描。您可以在SQL Fiddle中使用它。

不幸的是,MySQL 不支持分析功能,但在应用程序级别上做基本相同的功能应该没有问题。只是SELECT ... ORDER BY TIMESTAMP,线性遍历结果,看看当前行和上一行有什么区别。

于 2012-05-11T11:50:08.837 回答
2

那是操场:

CREATE TABLE `feed`(
  `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
  `tm` INT UNSIGNED NOT NULL COMMENT 'timestamp',
  `user_id` INT UNSIGNED NOT NULL COMMENT 'author id',
  `image` VARCHAR(255) NOT NULL COMMENT 'posted image filename',
  `group` INT UNSIGNED NULL DEFAULT NULL COMMENT 'post group',
  PRIMARY KEY(`id`),
  INDEX(`user_id`),
  INDEX(`tm`,`group`)
  );

我们想将时间上接近的帖子组合在一起。

首先,声明所需的粒度:时间接近度的阈值:

SET @granularity:=60*60;

每行形成一个组,组 ID 与行 ID 匹配(也可以是时间戳):

SELECT `g`.`id` AS `group`
FROM `feed` `g`;

每个组包含来自同一用户的行,发布时间早于 group-former:

SELECT `g`.`id` AS `group`, `f`.*
FROM `feed` `g`
    CROSS JOIN `feed` `f`
    ON (`f`.`user_id` = `g`.`user_id` 
        AND `f`.`tm` BETWEEN `g`.`tm`-@granularity AND `g`.`tm`
    )

每行属于多个组。对于每一行,我们选择最“广泛”的组:它具有最大的 rowId

SELECT MAX(`g`.`id`) AS `group`, `f`.*
FROM `feed` `g`
    CROSS JOIN `feed` `f`
    ON (`f`.`user_id` = `g`.`user_id` 
        AND `f`.`tm` BETWEEN `g`.`tm`-@granularity AND `g`.`tm`
    )
GROUP BY `f`.`id`

最近更新的组总是跳到顶部(如果您按groupDESC 排序)。但是,如果您希望这些组是持久的(例如,这样项目不会从一个组移动到另一个组),请使用MIN代替MAX

SELECT MIN(`g`.`id`) AS `group`, `f`.*
FROM `feed` `g`
    CROSS JOIN `feed` `f`
    ON (`f`.`user_id` = `g`.`user_id` 
        AND `f`.`tm` BETWEEN `g`.`tm` AND `g`.`tm`+@granularity
    )
GROUP BY `f`.`id`

现在,我们将更新表格的group列。首先,MySQL 无法更新您正在读取的同一张表。我们需要一个临时表。第二:我们只更新列为groupNULL 的行,或者发布晚于的行UNIX_TIMESTAMP()-2*@threshold

CREATE TEMPORARY TABLE `_feedg`
SELECT MAX(`g`.`id`) AS `group`, `f`.`id`
FROM `feed` `g`
    CROSS JOIN `feed` `f`
    ON (`f`.`user_id` = `g`.`user_id` 
        AND `f`.`tm` BETWEEN `g`.`tm`-@granularity AND `g`.`tm`
    )
WHERE `f`.`group` IS NULL 
    OR `f`.`tm` >= (UNIX_TIMESTAMP()-2*@granularity)
GROUP BY `f`.`id`;

并更新group列:

UPDATE `feed` `f` CROSS JOIN `_feedg` `g` USING(`id`)
SET `f`.`group` = `g`.`group`;

这是 SQLFiddle:http ://sqlfiddle.com/#!2/be9ce/15

于 2012-05-13T19:41:55.510 回答
1

“o_O Tync”的解决方案不会在 1 小时内对添加的项目进行分组,例如:1:00、1:40、2:30。只有最后两个将被分组。

这是没有临时表和连接(同一张表)的超快 Mysql 解决方案。

创建表`饲料`(
  `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
  `tm` INT UNSIGNED NOT NULL COMMENT 'timestamp',
  `user_id` INT UNSIGNED NOT NULL COMMENT 'author id',
  `image` VARCHAR(255) NOT NULL COMMENT '发布的图像文件名',
  `group` INT UNSIGNED NULL DEFAULT NULL COMMENT 'post group',
  主键(`id`),
  索引(`user_id`),
  索引(`tm`,`组`)
  );


SET @粒度:=60*60;
更新提要 f CROSS JOIN (
  选择
    g.id,
    @id:=COALESCE(IF(ISNULL(@prev_date) OR (user_id!=@prev_user_id) OR NOT(@prev_date-tm BETWEEN 0 AND @granularity), g.id, NULL), @id)
    +最少(0,@prev_date:=tm)
    +least(0, @prev_user_id:=user_id) 作为 group_id    
  FROM (SELECT @prev_date:=null, @id:=null, @user_id:=null) r, feed g
  ORDER BY user_id DESC, tm DESC
) z 使用 (id)
SET f.group = z.group_id;

http://sqlfiddle.com/#!2/02a98/1/0

于 2012-08-24T13:20:35.203 回答