0

我有一个将用户数据发送到云的客户端-服务器应用程序(Amazon EC2 + RDS + S3)。

  1. 每个用户都可以有多个设备连接到云端并同时发送数据
  2. 安装在每台设备上的客户端应用程序是多线程的,最终会同时上传多个数据片段。

我想可靠地跟踪在这种情况下使用的磁盘使用情况,我想知道如何在这种情况下做到这一点?

到目前为止,我有两个想法,但我什至不确定它们是否正确:

选项 1:向 mysql 表添加触发器?IE。

CREATE TRIGGER DiskUsage AFTER UPDATE OF Fully_Updated_File_Flag ON Files
BEGIN
    for each row
    begin
        UPDATE Users SET SpaceUsed = SpaceUsed + new.Size WHERE (new.Fully_Updated_File_Flag = 1) And UserID=
    end
END;

如果我选择使用触发器,我应该如何动态注入用户 ID?


选项 2:通过 PHP 更新 mysql 表?IE。

<?php

  SendFileToS3($file_name);
  mysql_query('UPDATE Stats SET Value = Value + ' . filesize($file_name) . ' WHERE user_id=' . $user_id);

?>

如果两个实例试图更新相同的记录怎么办?(我正在使用 Mysql 5.5.27-log / MyISAM),这仍然有效。


Note #1虽然我还没有发布我的应用程序,但我仍然需要一些可以很好地扩展的东西。即使这意味着一起更改数据库引擎。

注意 #2 DB 相关代码封装在模块化函数中(即 InsertIntoDB()、UpdateDB() 和 DeleteFromDB())。此外,所有这些例程都依赖于具有活动记录类的 CodeIgniter 2.1。

这就是说,如果必须,我总是可以进行切换尽管我想避免这种情况)

4

3 回答 3

3

您应该使用 MySQL 触发器而不是 PHP 代码,并且您必须将相关信息存储user_iddiskusage表中。

我使用InnoDB引擎是因为CONSTRAINT. 您也可以使用MyISAM,但您应该删除CONSTRAINT.

评论

我会使用InnoDB因为Transactions和(在这里更重要)Row-Locking

表结构(InnoDB)

-- ----------------------------
--  Table structure for `users`
-- ----------------------------
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
  `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  `Name` VARCHAR(10) NOT NULL DEFAULT '',
  `SpaceUsed` BIGINT(20) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;

-- ----------------------------
--  Table structure for `diskusage`
-- ----------------------------
DROP TABLE IF EXISTS `diskusage`;
CREATE TABLE `diskusage` (
  `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  `Filename` VARCHAR(50) NOT NULL DEFAULT '',
  `Size` BIGINT(20) NOT NULL,
  `user_id` INT(11) UNSIGNED DEFAULT NULL,
  `Fully_Updated_File_Flag` TINYINT(4) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `fk_diskusage_user` (`user_id`),
  CONSTRAINT `fk_diskusage_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=INNODB DEFAULT CHARSET=utf8;

表结构(MyISAM)

-- ----------------------------
--  Table structure for `users`
-- ----------------------------
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
  `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  `Name` VARCHAR(10) NOT NULL DEFAULT '',
  `SpaceUsed` BIGINT(20) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

-- ----------------------------
--  Table structure for `diskusage`
-- ----------------------------
DROP TABLE IF EXISTS `diskusage`;
CREATE TABLE `diskusage` (
  `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  `Filename` VARCHAR(50) NOT NULL DEFAULT '',
  `Size` BIGINT(20) NOT NULL,
  `user_id` INT(11) UNSIGNED DEFAULT NULL,
  `Fully_Updated_File_Flag` TINYINT(4) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `fk_diskusage_user` (`user_id`),
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

就是这样,再加上 table 上的一些触发器diskusage

插入触发器

-- ----------------------------
--  AFTER INSERT TRIGGER for `diskusage`
-- ----------------------------
delimiter ;;
CREATE TRIGGER `diskusage_after_insert` AFTER INSERT ON `diskusage` FOR EACH ROW BEGIN
  IF NEW.Fully_Updated_File_Flag = 1 THEN
    UPDATE users
    SET
      SpaceUsed = SpaceUsed + NEW.Size
    WHERE
      id = NEW.user_id;
  END IF;
END;
 ;;
delimiter ;

更新触发器

-- ----------------------------
--  AFTER UPDATE TRIGGER for `diskusage`
-- ----------------------------
delimiter ;;
CREATE TRIGGER `diskusage_after_update` AFTER UPDATE ON `diskusage` FOR EACH ROW BEGIN

  -- same to DELETE TRIGGER

  -- decrease SpaceUsed with OLD Size for OLD user

  IF OLD.Fully_Updated_File_Flag = 1 THEN
    UPDATE users
    SET
      SpaceUsed = SpaceUsed - OLD.Size
    WHERE
      id = OLD.user_id;
  END IF;

  -- same to INSERT TRIGGER

  -- increase SpaceUsed with NEW Size for NEW user

  IF NEW.Fully_Updated_File_Flag = 1 THEN
    UPDATE users
    SET
      SpaceUsed = SpaceUsed + NEW.Size
    WHERE
      id = NEW.user_id;
  END IF;

END;
 ;;
delimiter ;

删除触发器

-- ----------------------------
--  AFTER DELETE TRIGGER for `diskusage`
-- ----------------------------
delimiter ;;
CREATE TRIGGER `diskusage_after_delete` AFTER DELETE ON `diskusage` FOR EACH ROW BEGIN

  IF OLD.Fully_Updated_File_Flag = 1 THEN
    UPDATE users
    SET
      SpaceUsed = SpaceUsed - OLD.Size
    WHERE
      id = OLD.user_id;
  END IF;

END;
 ;;
delimiter ;
于 2013-01-04T08:51:52.533 回答
3

如果您正在跟踪文件、大小和所有权,SELECT SUM(Size) FROM Files WHERE UserID = ?那么在正确索引的表上执行此操作会非常快,除非用户有与他们相关联的大量文件。无需存储可以轻松计算的数字。

于 2013-01-03T18:06:54.257 回答
2

MyISAM 表的操作是原子的。基本上,查询发生后会自动提交。

此外,UPDATEs 是阻塞的,这意味着一次只能发生一个。

这意味着读写周期UPDATE不会被中断。

MySQL对 MyISAM 表使用表锁定。

这相当快,并且将确保并发更新正常工作。

但是,大量更新可能会导致表花费大量时间被锁定。如果表中有很多行,这可能会出现问题。

InnoDB 表支持行锁定。这需要更多资源,但如果您的表变大,可能会更合适。它使您可以更好地控制锁定,并允许多个不相关的进程访问表,而不会出现过多的锁定争用。

于 2013-01-03T18:04:01.553 回答