假设我有一个正常的规范化数据库,如下所示:
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语句,它很糟糕。 (对于具有~2百万行的数据库,它需要超过一分钟而不是少于一秒的数据表上的相同查询。 我的猜测是,为每一行执行用于获取用户和组的友好名称的select语句而不是缓存。 我该如何优化呢?
答案 0 :(得分:3)
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中的内部选择比连接慢得多。
答案 1 :(得分:1)
你有没有理由不使用连接?看起来您的查询可以按如下方式重写:
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,我建议您创建一个Indexed视图,但在MySQL中这不是一个选项。
答案 2 :(得分:0)
MySQL中的视图通常非常糟糕,因为优化器无法有效地优化它们。
但是如果你把它重写为一个连接(正如其他人建议的那样)并且不会让它变得更复杂,那应该没问题。