0

ユーザーデータをクラウドに送信するクライアントサーバーアプリケーションがあります(Amazon EC2 + RDS + S3)。

  1. すべてのユーザーは、クラウドに接続して同時にデータを送信する複数のデバイスを持つことができます
  2. 各デバイスにインストールされているクライアントアプリケーションはマルチスレッドであり、最終的には複数のデータスニペットを同時にアップロードします。

このコンテキストで使用されるディスク使用量を確実に追跡したいのですが、このコンテキストでこれを行う方法を知りたいですか?

これまでに2つのアイデアがありますが、それらが正しいかどうかさえわかりません。

オプション1:mysqlテーブルにトリガーを追加しますか?すなわち。

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テーブルを更新しますか?すなわち。

<?php

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

?>

2つのインスタンスが同じレコードを更新しようとしている場合はどうなりますか?(私はMysql 5.5.27-log / MyISAMを使用しています)、これはまだ機能しますか?


注#1アプリケーションはまだリリースしていませんが、拡張性に優れたものが必要です。たとえそれがdbエンジンを一斉に変更することを意味するとしても。

注#2 DB関連のコードは、モジュラー関数(InsertIntoDB()、UpdateDB()、およびDeleteFromDB())にカプセル化されています。さらに、これらのルーチンはすべて、アクティブレコードクラスを備えたCodeIgniter2.1に依存しています。

これは、必要に応じていつでも切り替えることができるということです(ただし、それは避けたいと思います)。

4

3 に答える 3

3

ファイル、サイズ、所有権を追跡しているSELECT SUM(Size) FROM Files WHERE UserID = ?場合、ユーザーが何億ものファイルを関連付けていない限り、適切にインデックス付けされたテーブルで実行するのは非常に高速です。簡単に計算できる数値を保存する必要はありません。

于 2013-01-03T18:06:54.257 に答える
3

PHPコードの代わりにMySQLトリガーを使用する必要があり、関連するものuser_iddiskusageテーブルに格納する必要があります。

InnoDBのせいでエンジンを使っていCONSTRAINTます。を使用することもできますMyISAMが、を削除する必要がありますCONSTRAINT

述べる

トランザクションと(ここでより重要な)行ロックInnoDBのために使用します。

テーブル構造(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;

それはすべて、テーブル上のいくつかのトリガーと一緒に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 に答える
2

MyISAMテーブルの操作はアトミックです。基本的に、クエリは発生後に自動的にコミットされます。

さらに、UPDATEsはブロックされています。つまり、一度に1つしか発生しません。

これは、の読み取り/書き込みサイクルUPDATEが中断されないことを意味します。

MySQLは、MyISAMテーブルにテーブルロックを使用します。

これはかなり迅速であり、同時更新が正しく機能することを保証します。

ただし、更新が多いと、テーブルがロックされるのに多くの時間がかかる可能性があります。テーブルに多くの行がある場合、これは問題になる可能性があります。

InnoDBテーブルは行ロックをサポートしています。これにはより多くのリソースが必要ですが、テーブルが大きくなる場合ははるかに適切な場合があります。これにより、ロックをより細かく制御でき、過度のロック競合なしに、複数の無関係なプロセスがテーブルにアクセスできるようになります。

于 2013-01-03T18:04:01.553 に答える