2017-01-21 7 views
0

У меня есть следующая схема:индекс не используется для рода в присоединился зрения

CREATE TABLE `news` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `news_category_id` int(10) unsigned NOT NULL, 
    `news_type_id` int(10) unsigned NOT NULL, 
    `news_pictures_main_id` int(10) unsigned DEFAULT NULL, 
    `title` tinytext COLLATE latin1_general_ci, 
    `body` text COLLATE latin1_general_ci, 
    `tmstp` timestamp NULL DEFAULT NULL, 
    `subcategory` varchar(64) COLLATE latin1_general_ci DEFAULT NULL, 
    `source` varchar(128) COLLATE latin1_general_ci DEFAULT NULL, 
    `old_id` int(10) unsigned DEFAULT NULL, 
    `tags` text COLLATE latin1_general_ci, 
    PRIMARY KEY (`id`), 
    KEY `news_time_idx` (`tmstp`), 
    KEY `fk_news_news_pictures1` (`news_pictures_main_id`), 
    KEY `fk_news_news_category1` (`news_category_id`), 
    KEY `fk_news_news_type1` (`news_type_id`), 
    CONSTRAINT `fk_news_news_category1` FOREIGN KEY (`news_category_id`) REFERENCES `news_category` (`id`) ON UPDATE CASCADE, 
    CONSTRAINT `fk_news_news_pictures1` FOREIGN KEY (`news_pictures_main_id`) REFERENCES `news_pictures` (`id`) ON DELETE SET NULL ON UPDATE CASCADE, 
    CONSTRAINT `fk_news_news_type1` FOREIGN KEY (`news_type_id`) REFERENCES `news_type` (`id`) ON UPDATE CASCADE 
) ENGINE=InnoDB 

CREATE TABLE `news_pictures` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `path` text COLLATE latin1_general_ci, 
    `description` text COLLATE latin1_general_ci, 
    `author` varchar(45) COLLATE latin1_general_ci DEFAULT NULL, 
    `news_id` int(10) unsigned DEFAULT NULL, 
    `temp_id` varchar(40) COLLATE latin1_general_ci DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `filename_old_id_unq` (`path`(20),`temp_id`(6)), 
    KEY `fk_news_pictures_news1` (`news_id`), 
    KEY `temp_id_idx` (`temp_id`(8)), 
    CONSTRAINT `fk_news_pictures_news1` FOREIGN KEY (`news_id`) REFERENCES `news` (`id`) ON DELETE CASCADE ON UPDATE CASCADE 
) ENGINE=InnoDB 

CREATE TABLE `news_category` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `name` varchar(45) COLLATE latin1_general_ci DEFAULT NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB 

CREATE TABLE `news_type` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `name` varchar(45) COLLATE latin1_general_ci DEFAULT NULL, 
    `slug` varchar(45) COLLATE latin1_general_ci DEFAULT NULL, 
    PRIMARY KEY (`id`) 
    KEY `news_type_slug_idx` (`slug`) 
) ENGINE=InnoDB 

От того, есть получается следующий вид:

CREATE OR REPLACE VIEW `news_full` AS select `n`.`id` AS `id`, 
`n`.`title` AS `title`, 
`n`.`body` AS `body`, 
`n`.`tmstp` AS `tmstp`, 
`n`.`subcategory` AS `subcategory`, 
`n`.`source` AS `source`, 
`n`.`old_id` AS `old_id`, 
`n`.`news_type_id` AS `news_type_id`, 
`n`.`tags` AS `tags`, 
`nt`.`name` AS `news_type_name`, 
`nt`.`slug` AS `news_type_slug`, 
`n`.`news_pictures_main_id` AS `news_pictures_main_id`, 
`np`.`path` AS `news_pictures_main_path`, 
`np`.`description` AS `news_pictures_main_description`, 
`np`.`author` AS `news_pictures_main_author`, 
`np`.`temp_id` AS `news_pictures_main_temp_id`, 
`n`.`news_category_id` AS `news_category_id`, 
`nc`.`name` AS `news_category_name` 
from (((`news` `n` 
      left join `news_pictures` `np` on((`n`.`news_pictures_main_id` = `np`.`id`))) 
     join `news_category` `nc` on((`n`.`news_category_id` = `nc`.`id`))) 
    join `news_type` `nt` on((`n`.`news_type_id` = `nt`.`id`))); 

Однако, если я пытаюсь запустить следующий запрос:

select * from news_full order by tmstp limit 100 

я получаю следующий план выполнения (пожалуйста, нажмите на изображение, чтобы увеличить его):

Explain result

Обратите внимание на Using temporary; Using filesort поле в первом шаге. Но это странно, потому что поле tmstp индексируется на базовой таблице.

Сначала я думал, что это было связано с left join на вид, но я изменил его на inner join, и у меня были те же результаты.


Редактировать

Как @ Michael-sqlbot умно заметил, оптимизатор запросов будет инвертировать порядок базовых таблиц, положив news_category (nc) первый.

Если изменить запрос, который создает вид использовать только LEFT JOIN сек, кажется, работает:

New query plan

Время выполнения, как и следовало ожидать, так как явно отличается: Query comparison

Не Доволен, я создал другое представление с исходным запросом, добавив оператор STRAIGHT_JOIN. Таким образом, план запроса приходит следующим образом:

Query plan - straight join

Таким образом, это не с помощью индекса.

Однако, если я запускаю план базового запроса, добавив то же ORDER BY и LIMIT положения, он делает использует индекс:

Query plan - straight join no view

+0

MySQL не может использовать индекс в представлении. Поэтому в MySQL не так много точек зрения. – Strawberry

+0

Я слышал, что вы не можете CREATE индексов в представлениях в MySQL, но он использует индексы из базовых таблиц для запуска запросов. Однако у меня нет никаких ссылок. Если у вас есть тот, который доказывает мне свою ошибку, не могли бы вы разместить его здесь? –

+0

http://dev.mysql.com/doc/refman/5.7/ru/view-restrictions.html –

ответ

1

(не ответ, но некоторые другие вопросы, воспитывать ...)

UNIQUE KEY `filename_old_id_unq` (`path`(20),`temp_id`(6)) 
  • Это сдерживает первые 20 символов path, а также первые 6 символов temp_id, чтобы быть уникальными через стол. Вы действительно этого хотели?
  • Я подозреваю, что оптимизатор будет никогда использовать обе колонки этого индекса. (В общем, префикс бесполезен.)

И ...

`title` tinytext COLLATE latin1_general_ci 

Изменения в VARCHAR(255). Есть недостатки TINYTEXT и, возможно, нет преимуществ.

+0

Об индексе это потому, что 'path' и' temp_id' имеют ширину 20 и 6 символов соответственно. Почему оптимизатор никогда не будет использовать оба столбца? У меня есть запрос с предложением WHERE, как 'WHERE path = $ 1 и temp_id = $ 2'. –

+0

Если они всегда 20 и 6 символов, то объявляйте столбцы «CHAR (20)» и «CHAR (6)», а затем удаляем «префикс» из индекса. _Then_ оптимизатор пройдет мимо усеченного первого столбца. –