MySQL中的快速反规范化视图,如何?

Posted

技术标签:

【中文标题】MySQL中的快速反规范化视图,如何?【英文标题】:Fast de-normalized View in MySQL, how? 【发布时间】:2011-04-03 21:14:13 【问题描述】:

假设我有一个像这样的正常规范化数据库:

CREATE TABLE `users` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(80) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;
INSERT INTO `users` (`id`, `name`) VALUES
(1, 'test'),
(2, 'user');

_

CREATE TABLE `groups` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(80) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;
INSERT INTO `groups` (`id`, `name`) VALUES
(1, 'test');

_

CREATE TABLE `Data` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `user` int(10) unsigned NOT NULL,
  `group` int(10) unsigned NOT NULL,
  `time` int(10) unsigned NOT NULL,
  `data` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (`id`),
  KEY `user` (`user`),
  KEY `group` (`group`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=3 ;

INSERT INTO `Data` (`id`, `user`, `group`, `time`, `data`) VALUES
(1, 2, 1, 1301861998, 'something'),
(2, 1, 1, 1301862045, 'something else');

ALTER TABLE `Data`
  ADD CONSTRAINT `Data_ibfk_2` FOREIGN KEY (`group`) REFERENCES `groups` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  ADD CONSTRAINT `Data_ibfk_1` FOREIGN KEY (`user`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;

现在我想创建一个视图,该视图显示该数据库已去规范化,以便于手动浏览。 如何正确创建此视图? 到目前为止我所拥有的是:

CREATE VIEW `data_view` AS
  select `Data`.`id`,
 (select `users`.`name` AS `name` from `users` where (`users`.`id` = `Data`.`user`)) AS `user`,
 (select `groups`.`name` AS `name` from `groups` where (`groups`.`id` = `Data`.`group`)) AS `group`,
 from_unixtime(`Data`.`time`) AS `time`,
 `Data`.`data` AS `data` from `Data`;

它可以工作,但是由于两个内部 SELECT 语句,它非常慢。 (对于具有约 200 万行的数据库,对于数据表上的相同查询,它需要超过一分钟而不是不到一秒。 我的猜测是,为每一行执行获取用户和组的友好名称的选择语句,而不是缓存。 我该如何优化它?

【问题讨论】:

谢谢大家的回答。很遗憾,我必须使用 mysql.... 不太喜欢它。但是使用连接它的工作速度足够快。 【参考方案1】:
CREATE VIEW `data_view` AS
  select `Data`.`id`,
  `users`.`name` as `user`,
  `groups`.`name` as `group`,
 from_unixtime(`Data`.`time`) AS `time`,
 `Data`.`data` AS `data` from `Data`
 INNER JOIN `users` ON (`users`.`id` = `Data`.`user`)
 INNER JOIN `groups` where (`groups`.`id` = `Data`.`group`)

试试这个。并确保 users.id、groups.id、data.user 和 data.group 是索引。

mysql 中的内部选择比连接慢得多。

【讨论】:

【参考方案2】:

您没有使用连接有什么原因吗?看起来您的查询可以重写如下:

SELECT d.id, u.name, g.name as GroupName, from_unixtime(d.time) as time
from Data as d
INNER JOIN users as u
ON d.user = u.id
INNER JOIN groups as g
ON d.group = g.id

然后我会看看你有哪些索引。如果可以通过添加索引来提高性能,您可能想要这样做,但请记住,拥有索引会加快选择速度并减慢插入/更新/删除速度,因此如果数据经常更新,您将不得不看看是否值得.

如果您使用的是 SQL Server,我建议您创建索引视图,但在 MySQL 中这不是一个选项。

【讨论】:

【参考方案3】:

MySQL 中的视图通常非常糟糕,因为优化器无法有效地优化它们。

但是,如果您将其重写为联接(如其他人建议的那样)并且不使其更复杂,那应该没问题。

【讨论】:

以上是关于MySQL中的快速反规范化视图,如何?的主要内容,如果未能解决你的问题,请参考以下文章

如何对 Kafka 中的数据进行反规范化?

DRF入门规范

MySQL中数据中设计中的范式与反范式

如何将多列“爆破”(反规范化/合并)成一列?

MySQL:视图与存储过程

《MySQL高级篇》九数据库的设计规范