Mysql一般的な水平表スキーム

3577 ワード

経験によると、Mysqlテーブルのデータは一般的に百万レベルに達し、クエリーの効率が低く、テーブルのロックを引き起こしやすく、多くの接続を積み上げ、直接切ることができます.水平メーターは、これらの圧力を大幅に少なくすることができます.
1.時間割表
このような表分け方式には一定の限界があり、マイクロブログ送信記録、マイクロメッセージ記録など、データの実効性が強い場合、このようなデータは数ヶ月前のデータを照会するユーザーは少なく、月ごとに表を分けることができる.
2.区間範囲別表
一般的にuser_id水平分表:
table_1  user_idは1~100 wから
table_2  user_idは101~200 wから
table_3  user_idは201~300 wから
... 
3.hash表
元のターゲットのIDまたは名前から一定のhashアルゴリズムでデータストアテーブルのテーブル名を計算し、対応するテーブルにアクセスします.
以下のように10枚の表に分けます.
function get_hash_table($table, $userid) 
{
    $str = crc32($userid);
    
    if ($str < 0) {
        $hash = "0" . substr(abs($str), 0, 1);
    } else {
        $hash = substr($str, 0, 2);
    }
 
    return $table . "_" . $hash;
}
 
echo get_hash_table('message', 'user18991'); //   message_10
echo get_hash_table('message', 'user34523'); //   message_13

型取り表:
/**
 * @param string $table_name   
 * @param int $user_id   id
 * @param int $total     
 * @link http://www.phpddt.com
 */
function hash_table($table_name, $user_id, $total)
{
    return $table_name . '_' . (($user_id % $total) + 1);
}
 
echo hash_table("artice", 1234, 5); //artice_5
echo hash_table("artice", 3243, 5); //artice_4

4.mergeストレージエンジンによる表分け
mergeストレージエンジンはsqlのunionのような感じがしますが、クエリーの効率は高くありません.
以下の例では、1000 wのレコードを持つold_userテーブルテーブル:
(1)new_の作成userテーブルmergeストレージエンジンの使用
mysql> CREATE TABLE IF NOT EXISTS `user1` (
 ->   `id` int(11) NOT NULL AUTO_INCREMENT,
 ->   `name` varchar(50) DEFAULT NULL,
 ->   `sex` int(1) NOT NULL DEFAULT '0',
 ->   PRIMARY KEY (`id`)
 -> ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
Query OK, 0 rows affected (0.05 sec)
 
mysql> CREATE TABLE IF NOT EXISTS `user2` (
 ->   `id` int(11) NOT NULL AUTO_INCREMENT,
 ->   `name` varchar(50) DEFAULT NULL,
 ->   `sex` int(1) NOT NULL DEFAULT '0',
 ->   PRIMARY KEY (`id`)
 -> ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
Query OK, 0 rows affected (0.01 sec)
 
mysql> INSERT INTO `user1` (`name`, `sex`) VALUES('  ', 0);
Query OK, 1 row affected (0.00 sec)
 
mysql> INSERT INTO `user2` (`name`, `sex`) VALUES('tank', 1);
Query OK, 1 row affected (0.00 sec)
 
mysql> CREATE TABLE IF NOT EXISTS `new_user` (
 ->   `id` int(11) NOT NULL AUTO_INCREMENT,
 ->   `name` varchar(50) DEFAULT NULL,
 ->   `sex` int(1) NOT NULL DEFAULT '0',
 ->   INDEX(id)
 -> ) TYPE=MERGE UNION=(user1,user2) INSERT_METHOD=LAST AUTO_INCREMENT=1 ;
Query OK, 0 rows affected, 1 warning (0.00 sec)
 
mysql> select id,name,sex from new_user;
+----+--------+-----+
| id | name   | sex |
+----+--------+-----+
|  1 |    |   0 |
|  1 | tank   |   1 |
+----+--------+-----+
2 rows in set (0.00 sec)
 
mysql> INSERT INTO `new_user` (`name`, `sex`) VALUES('tank2', 0);
Query OK, 1 row affected (0.00 sec)
 
mysql> select id,name,sex from user2
 -> ;
+----+-------+-----+
| id | name  | sex |
+----+-------+-----+
|  1 | tank  |   1 |
|  2 | tank2 |   0 |
+----+-------+-----+
2 rows in set (0.00 sec)

私はold_userデータをテーブル化するには、次の手順に従います.
このシナリオの最大の利点は、ビジネスコードをほとんど使用しないことです.
INSERT INTO user1(user1.id,user1.name,user1.sex) SELECT (user.id,user.name,user.sex)FROM old_user where user.id <= 5000000
INSERT INTO user2(user2.id,user2.name,user2.sex) SELECT (user.id,user.name,user.sex)FROM old_user where user.id > 10000000