Index
我應該規範化這個數據庫嗎?
我有兩種用於在使用者之間儲存消息(即時消息)的數據庫設計。這將是一個群聊系統。
我想到了兩種桌子設計。
一個是這樣的:
CREATE TABLE `mssg_grp_user` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `user_id` int(10) unsigned NOT NULL, `grp_id` int(10) unsigned NOT NULL, `body` varchar(100) COLLATE utf8_unicode_ci NOT NULL, `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', PRIMARY KEY (`created_at`,`grp_id`,`user_id`,`id`), KEY `mssg_grp_user_user_id_foreign` (`user_id`), KEY `mssg_grp_user_grp_id_foreign` (`grp_id`), KEY `mssg_id_is` (`id`), CONSTRAINT `mssg_grp_user_grp_id_foreign` FOREIGN KEY (`grp_id`) REFERENCES `groups` (`id`) ON UPDATE CASCADE, CONSTRAINT `mssg_grp_user_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON UPDATE CASCADE ) ENGINE=InnoDB AUTO_INCREMENT=350201 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
在第二個中: Messages 表具有以下鍵
alter table messages drop primary key , add primary key (created_at, id), add INDEX mssg_id_ix (id) ;
並且在mssg_grps表中有一個主鍵(grp_id,mssg_id)。
我的主要查詢是檢索組 ID 列表中的最新 50 條消息,並且比某個時間更新。對於第二個,我執行了這個查詢:
SELECT * FROM test.mssg_grp a LEFT JOIN test.messages b ON a.mssg_id = b.id Where b.created_at >"1970-01-03 19:08:21" AND a.grp_id IN(8,2,1,2,5,6,3) order by created_at limit 50;
這花了很長時間。一個查詢(有 20 萬條消息)需要 0.1 秒,100 個並髮使用者大約需要 2 分鐘。
然後我決定合併表(即更改我的數據庫模式)並切換到第一個。
為了獲得相同的數據,我執行了這個查詢:
Select sql_no_cache * from test.mssg_grp_user where grp_id IN (8,1,5,6,7,8,9) and created_at>888880 order by created_at desc limit 50;
對於100 個並髮使用者,這需要 0.1 秒。這顯然要快得多。我的問題是:
- 為什麼加入+訂單需要這麼多時間?
- 我應該切換到第一個設計嗎?(正文欄位最多可以有 500 個字元)
第一個解決方案顯然比第二個更有效,因為您不需要執行連接(每個連接都會減慢查詢速度,或多或少取決於系統生成的訪問計劃)。
更多,我認為第二種解決方案有一些問題,因為從架構看來,您使用
id
裡面的列mssg_grp
作為引用表的外鍵mssg
,而在該表中,您使用的幾列created_at
和作為主鍵id
,這與外鍵的定義,從中可以假設它id
已經是mssg
.因此,如果從圖中看起來,和之間的關係
mssg
是mssg_grp
1:1,那麼您應該選擇仍然標準化且更有效的第一個解決方案。
1)左連接比內連接慢。這是第一個原因。二是為優化查詢添加特殊索引。使用查詢的解釋計劃
2)如果你想使用結果表,那麼我建議你使用材料視圖。它會更快,你可以不考慮欄位的長度。
ps View 不是表格,因此您將節省時間,而不是在第三個表格中插入