首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >什么是存储和计算用户点数的好的、灵活的方法?

什么是存储和计算用户点数的好的、灵活的方法?
EN

Stack Overflow用户
提问于 2018-10-09 23:51:00
回答 2查看 64关注 0票数 0

我想为不同的促销活动向用户表示感谢。例如,在写文章时,给文章打分……

我正在寻找一个灵活的解决方案,其中我可以调整不同的行动和总分也变化的分数。

如果我将这些点保存在一个表中,以后就不能再更改它们了。如下所示:

代码语言:javascript
复制
$request->user()->points += 10;
    $request->user()->save();

当我每次重新计算分数时,性能如何?如下所示:

代码语言:javascript
复制
$articlepoints = $user->articles->count();
&votepoints = $user->votes->count();
$totalpoints = $articlepoints*10+$votepoints*5; 

还有没有别的选择?

EN

回答 2

Stack Overflow用户

发布于 2018-10-10 03:02:12

如果您试图最小化每个负载上的计数操作,则可以使用Cache::remember()方法。你只需要决定你想要多长时间“过期”这个cccced值。我假设你将在用户模型中运行这个函数,但是你可以在任何你想要的地方运行它:

代码语言:javascript
复制
$articlepoints = Cache::remember('articlepoints_'.$this->id, 5, function () {
    return $this->articles->count();
});

这段代码的作用是检查缓存中"articlepoints_userID“索引下是否存在该用户的文章指针。userID是动态的,将为每个用户存储不同的值。如果该索引存在,则将其用作值。

如果索引还不存在于缓存中,您可以将其传递到函数中,在函数中返回计算出的值并将其存储5分钟。您可以对等式中的每个值(投票点和累计点)执行此操作,并使用您想要的任何过期时间。

使用这段代码,可以极大地减少对count()函数的调用。但是,根据缓存驱动程序的不同,您可能仍然需要对其中的每一个进行数据库调用或磁盘调用。为了避免这种类型的开销,您需要研究不同的缓存驱动程序,例如redis。

查看Laravel Cache docs,看看您可以使用缓存做的所有其他很酷的事情。学习缓存系统是提高Laravel应用程序性能的好方法。

票数 0
EN

Stack Overflow用户

发布于 2018-10-10 03:25:19

这类事情的一种常见模式是保留一个表,以记录导致积分的每个事件,并在用户表或某种包含每个用户的记录的统计数据表上的列中聚合总积分。这使您能够保留每个事件的记录,如果您更改了每个事件类型的价值,则可以追溯地重新计算总计,并且可以访问总计(并在查询中使用它们),而不必每次都计算它们。

当我做这类事情时,我使用数据库中的触发器在存储事件时自动更新聚合总数,以便应用程序逻辑保持整洁。下面是一个适用于MySQL的示例:

代码语言:javascript
复制
CREATE TABLE `users` (
  `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  `username` varchar(20) NOT NULL,
  `total_activity_points` int(11) UNSIGNED NOT NULL DEFAULT 0,
  PRIMARY KEY (`id`),
  UNIQUE KEY `users_username_uk` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

INSERT INTO `users` (`username`) VALUES ('Bob');
INSERT INTO `users` (`username`) VALUES ('Alice');

CREATE TABLE `activities` (
  `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  `title` varchar(20) NOT NULL,
  `points` int(11) UNSIGNED NOT NULL DEFAULT 0,
  PRIMARY KEY (`id`),
  UNIQUE KEY `activities_title_uk` (`title`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

INSERT INTO `activities` (`title`,`points`) VALUES ('Article', 10);
INSERT INTO `activities` (`title`,`points`) VALUES ('Vote', 5);

CREATE TABLE `user_activities` (
  `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  `user_id` int(11) UNSIGNED NOT NULL,
  `activity_id` int(11) UNSIGNED NOT NULL,
  `create_date` DATETIME NOT NULL,
  PRIMARY KEY (`id`),
  CONSTRAINT `user_activities_fk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE,
  CONSTRAINT `user_activities_fk_2` FOREIGN KEY (`activity_id`) REFERENCES `activities` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

DELIMITER //
DROP TRIGGER IF EXISTS `after_insert_user_activities` //
CREATE TRIGGER `after_insert_user_activities`
  AFTER INSERT
  ON `user_activities`
  FOR EACH ROW
  BEGIN
    DECLARE v_total INTEGER DEFAULT 0;
    SET v_total = (SELECT SUM(`activities`.`points`)
                   FROM `user_activities`
                   INNER JOIN `activities` ON `activities`.`id`=`user_activities`.`activity_id`
                   WHERE `user_activities`.`user_id` = NEW.`user_id`);
    UPDATE `users`
    SET `total_activity_points` = v_total
    WHERE `users`.`id` = NEW.`user_id`;
  END;
//
DELIMITER ;

DELIMITER //
DROP TRIGGER IF EXISTS `after_delete_user_activities` //
CREATE TRIGGER `after_delete_user_activities`
  AFTER DELETE
  ON `user_activities`
  FOR EACH ROW
  BEGIN
    DECLARE v_total INTEGER DEFAULT 0;
    SET v_total = (SELECT SUM(`activities`.`points`)
                   FROM `user_activities`
                     INNER JOIN `activities` ON `activities`.`id`=`user_activities`.`activity_id`
                   WHERE `user_activities`.`user_id` = OLD.`user_id`);
    UPDATE `users`
    SET `total_activity_points` = v_total
    WHERE `users`.`id` = OLD.`user_id`;
  END;
//
DELIMITER ;

INSERT INTO `user_activities` (`user_id`,`activity_id`,`create_date`) VALUES (1,1,NOW());
INSERT INTO `user_activities` (`user_id`,`activity_id`,`create_date`) VALUES (1,2,NOW());
INSERT INTO `user_activities` (`user_id`,`activity_id`,`create_date`) VALUES (2,2,NOW());
INSERT INTO `user_activities` (`user_id`,`activity_id`,`create_date`) VALUES (2,2,NOW());

DELIMITER //
DROP TRIGGER IF EXISTS `after_update_activities` //
CREATE TRIGGER `after_update_activities` AFTER UPDATE ON `activities`
  FOR EACH ROW
  BEGIN
    DECLARE v_finished INTEGER DEFAULT 0;
    DECLARE v_userId INT(11) UNSIGNED;
    DECLARE v_total INT(11) UNSIGNED;

    DECLARE user_id_cursor CURSOR FOR SELECT DISTINCT(`user_activities`.`user_id`) FROM `user_activities` WHERE `user_activities`.`activity_id`=NEW.`id`;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_finished = 1;

    IF NEW.`points` != OLD.`points` THEN
      OPEN user_id_cursor;

      get_user_ids: LOOP
        FETCH user_id_cursor INTO v_userId;
        IF v_finished = 1 THEN
          LEAVE get_user_ids;
        END IF;
        -- recalculate and store scores
        SET v_total = (SELECT SUM(`activities`.`points`)
                       FROM `user_activities`
                         INNER JOIN `activities` ON `activities`.`id`=`user_activities`.`activity_id`
                       WHERE `user_activities`.`user_id` = v_userId);
        UPDATE `users`
        SET `total_activity_points` = v_total
        WHERE `users`.`id` = v_userId;
      END LOOP get_user_ids;

      CLOSE user_id_cursor;
    END IF;
  END;
//
DELIMITER ;

DELIMITER //
DROP TRIGGER IF EXISTS `before_delete_activities` //
CREATE TRIGGER `before_delete_activities` BEFORE DELETE ON `activities`
  FOR EACH ROW
  BEGIN
    DECLARE v_finished INTEGER DEFAULT 0;
    DECLARE v_userId INT(11) UNSIGNED;
    DECLARE v_total INT(11) UNSIGNED;

    DECLARE user_id_cursor CURSOR FOR SELECT DISTINCT(`user_activities`.`user_id`) FROM `user_activities` WHERE `user_activities`.`activity_id`=OLD.`id`;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_finished = 1;

    OPEN user_id_cursor;

    get_user_ids: LOOP
      FETCH user_id_cursor INTO v_userId;
      IF v_finished = 1 THEN
        LEAVE get_user_ids;
      END IF;
      -- recalculate and store scores
      SET v_total = (SELECT SUM(`activities`.`points`)
                     FROM `user_activities`
                       INNER JOIN `activities` ON `activities`.`id`=`user_activities`.`activity_id`
                     WHERE `user_activities`.`user_id` = v_userId
                     AND  `user_activities`.`activity_id` != OLD.`id`);
      UPDATE `users`
      SET `total_activity_points` = v_total
      WHERE `users`.`id` = v_userId;
    END LOOP get_user_ids;

    CLOSE user_id_cursor;
  END;
//
DELIMITER ;

当点值发生更改或活动被删除时,activities表中的触发器会更新总计。before delete触发器是必需的,因为MySQL不对级联删除运行delete触发器。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52724923

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档