Быстрый денормализованный вид в MySQL, как? - PullRequest
2 голосов
/ 04 апреля 2011

Допустим, у меня есть нормальная нормализованная база данных, подобная этой:

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 для получения понятных имен для пользователя и группы выполняются длякаждая строка и не кэшируется. Как я могу оптимизировать это?

Ответы [ 3 ]

3 голосов
/ 04 апреля 2011
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 голос
/ 04 апреля 2011

Есть ли причина, по которой вы не используете объединения?Похоже, ваш запрос можно переписать следующим образом:

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 это не вариант.

0 голосов
/ 04 апреля 2011

Представления в MySQL обычно очень плохие, потому что оптимизатор не может эффективно их оптимизировать.

Но если вы переписываете это как объединение (как предлагали другие) и не усложняете, все будет хорошо.

...