MySQL 中快速非规范化视图,如何实现?

发布于 2024-10-30 00:37:51 字数 1953 浏览 2 评论 0原文

比方说,我有一个像这样的正常规范化数据库:

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 万行的数据库,对数据表执行相同的查询需要超过一分钟而不是不到一秒。 我的猜测是,为每行执行获取用户和组的友好名称的 select 语句,而不是缓存。 我该如何优化这个?

Let's say, I have a normal normalized database like this:

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;

Now I want to create a view, that shows this database de-normalized for easier manual browsing.
How do I properly create this view?
What I have so far is:

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`;

It works, but because of the two inner SELECT statements it is awfull awfull slow. (for a DB with ~2 Million rows it needs more than a minute instead of less then a second for the same query on the data table.
My guess is, that the select statements to get the friendly names for user and group are executed for each row and not cached.
How can I optimize this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

戴着白色围巾的女孩 2024-11-06 00:37:51
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

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

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`)

try this. and make sure, that users.id, groups.id, data.user and data.group are indexes..

inner selects in mysql are much slower than joins.

眼眸里的那抹悲凉 2024-11-06 00:37:51

您有什么理由不使用联接吗?看起来您的查询可以重写如下:

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 中这不是一个选项。

Is there any reason you aren't using joins? It looks like your query can be rewritten as follows:

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

I would then look at what indexes you have in place. If your performance can be improved by adding an index you may want to do it, but keep in mind that having indexes speeds up selects and slows down inserts/updates/deletes so if data is updated frequently you will have to see if it's worth it.

If you were using SQL Server I would recommend creating an Indexed view, but in MySQL this is not an option.

︶ ̄淡然 2024-11-06 00:37:51

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

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

Views in MySQL generally suck really badly, because the optimiser can't effectively optimise them.

But if you rewrite that as a join (as others suggested) and don't make it more complicated, it should be fine.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文