提高数据库速度的一种方法是非规范化。以MySQL为例:
CREATE TABLE `users` (
`user_id` INT NOT NULL AUTO_INCREMENT,
⦠-- Additional user data
PRIMARY KEY (`user_id`)
);
CREATE TABLE `roles` (
`role_id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(64),
PRIMARY KEY (`role_id`)
);
CREATE TABLE `users_roles` (
`user_id` INT NOT NULL,
`role_id` INT NOT NULL,
PRIMARY KEY (`user_id`, `role_id`)
);
整洁、干净、正常。但是,如果你想获取用户及其角色,查询很复杂:
SELECT u.*, r.*
FROM `users` u
LEFT JOIN `user_roles` ur ON u.`user_id` = ur.`user_id`
JOIN `roles` r ON ur.`role_id` = r.`role_id`;
如果你将其非标准化,它可能看起来像:
CREATE TABLE `users` (
`user_id` INT NOT NULL AUTO_INCREMENT,
`role` VARCHAR(64),
⦠-- Additional user data
PRIMARY KEY (`user_id`)
);
等效的查询将是:
SELECT * FROM `users`;
这改善了查询的一些性能特征:
-
因为您想要的结果已经在表中,所以您不必执行读取端计算。例如,如果你想查看具有给定角色的用户数量,你需要
GROUP BY
和
COUNT
。如果它被非规范化,您将把它存储在一个不同的表中,该表专门用于保存角色和具有该角色的用户计数。
-
您想要的数据在同一个地方,希望在磁盘上的同一个位置。您可以进行一到几次顺序读取,而不是需要多次随机查找。
这种性能的权衡是写负载、磁盘空间和一些应用程序的复杂性。对数据进行反规范化意味着需要更多的副本,这意味着需要更大的磁盘空间和写负载。本质上,每个查询都有一个数据集。因为你将这些计算的负担转移到了写入时间而不是读取时间,所以你真的需要某种异步机制来实现这一点,从而增加了应用程序的复杂性。
而且因为你必须存储更多的副本,所以你必须执行更多的写入操作。这就是为什么你实际上无法用SQL数据库复制这种架构——扩展写入非常困难。
根据我的经验,对于大规模应用程序来说,这种权衡是值得的。如果你想了解更多关于Cassandra的实际应用,
I wrote this piece
几个月前,你可能会发现它很有帮助。