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枚の表に分けます.
型取り表:
4.mergeストレージエンジンによる表分け
mergeストレージエンジンはsqlのunionのような感じがしますが、クエリーの効率は高くありません.
以下の例では、1000 wのレコードを持つold_userテーブルテーブル:
(1)new_の作成userテーブルmergeストレージエンジンの使用
私はold_userデータをテーブル化するには、次の手順に従います.
このシナリオの最大の利点は、ビジネスコードをほとんど使用しないことです.
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