Альтернатива подзапросу - PullRequest
0 голосов
/ 21 октября 2011

С учетом следующих таблиц:

CREATE TABLE IF NOT EXISTS `rank` ( 
`rank_id` bigint(20) NOT NULL AUTO_INCREMENT, 
`rank` int(10) NOT NULL DEFAULT '0', 
`subject_id` int(10) NOT NULL DEFAULT '0', 
`title_id` int(10) NOT NULL DEFAULT '0', 
`source_id` int(10) NOT NULL DEFAULT '0'
PRIMARY KEY (`rank_id`) 
) ENGINE=MyISAM; 

INSERT INTO `rank` (`rank_id`, `rank`, `subject_id`, `title_id`, `source_id`) VALUES 
(23, 0, 2, 1, 1), 
(22, 0, 1, 1, 1), 
(15, 0, 2, 2, 2), 
(14, 0, 2, 2, 1), 
(20, 0, 1, 3, 2), 
(18, 0, 1, 4, 2), 
(19, 0, 1, 5, 2), 
(21, 0, 1, 3, 1), 
(24, 0, 1, 6, 2); 

CREATE TABLE IF NOT EXISTS `title` ( 
`title_id` bigint(20) NOT NULL AUTO_INCREMENT, 
`title` varchar(255) DEFAULT NULL, 
`description` text, 
`pre` varchar(255) DEFAULT NULL, 
`last_modified_by` varchar(50) DEFAULT NULL, 
`last_modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, 
PRIMARY KEY (`title_id`) 
) ENGINE=MyISAM; 

INSERT INTO `title` (`title_id`, `title`, `last_modified`) VALUES 
(1, 'new item', ' ', '2011-10-20 19:10:48'), 
(2, 'another test', '2011-10-20 19:10:48'), 
(3, 'and yet another', '2011-10-20 19:10:48'), 
(4, 'one more', ' ', '2011-10-20 19:10:48'), 
(5, 'adding more', ' ', '2011-10-20 19:10:48'), 
(6, 'yes, another', ' ', '2011-10-20 19:10:48'), 
(7, 'well, let''s see', ' ', '2011-10-20 19:10:48'); 

Мне нужен запрос для выбора всех заголовков, которые не связаны с данной темой в таблице рангов.

У меня это работает через подзапрос:

SELECT title_id, title FROM title
WHERE title_id NOT IN (SELECT title_id FROM rank WHERE subject_id=2)

Возвращает желаемый список:

+----------+-----------------+ 
| title_id | title           | 
+----------+-----------------+ 
| 3        | and yet another | 
| 4        | one more        | 
| 5        | adding more     | 
| 6        | yes, another    | 
| 7        | well, let's see | 
+----------+-----------------+ 

Однако, он становится немного медленным, когда большой наборданные запрашиваются.

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

Заранее спасибо.

Ответы [ 3 ]

3 голосов
/ 21 октября 2011

MySQL обычно быстрее с объединениями, хотя в данный момент работают более быстрые подзапросы.

SELECT t.*
FROM title AS t
LEFT JOIN rank AS r ON (t.title_id = r.title_id AND r.subject_id = 2)
WHERE r.title_id IS NULL

Как обычно, вам нужно настроить индексы для внешнего ключа (rank.title_id) и, возможно, для запрашиваемого ключа (rank.subject_id).

Вы должны прочитать документацию по MySQL на [LEFT JOIN][1], если хотите узнать больше. Есть также хороший трюк с ON, который отличает его от WHERE.

1 голос
/ 21 октября 2011

Пожалуйста, создайте два индекса для subject_id и title_id и попробуйте тоже самое.

1 голос
/ 21 октября 2011

Команда MySQL EXPLAIN сообщит вам, где ваш запрос нуждается в помощи. например EXPLAIN select title_id, title FROM title WHERE title_id NOT IN (select title_id from rank where subject_id=2)

Я предполагаю, что настоящая проблема в том, что у вас нет индекса для rank.subject_id, и это вызывает сканирование таблицы (когда у ранга много строк).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...