Оптимизация SQL-запроса для отношения «многие к одному»

У меня есть две таблицы с отношением «многие к одному», которые я назову Parent_Table и Child_Table (т. е. у родителя ноль или более дочерних элементов, но у дочерних элементов ровно один родитель). Мне нужно подсчитать количество родителей, у которых есть хотя бы один ребенок, удовлетворяющий некоторому условию. Какой запрос оптимален?

Вариант 1 (уверен, что это не тот)

SELECT COUNT(DISTINCT(pt.ID)) 
FROM PARENT_TABLE pt
JOIN CHILD_TABLE ct
ON pt.ID =  ct.PARENT_ID
WHERE <parent meets some condition>
AND <child meets some condition>

Вариант 2

SELECT COUNT(pt.ID)
FROM PARENT_TABLE pt
WHERE pt.ID in
(
SELECT ct.PARENT_ID
FROM CHILD_TABLE ct
WHERE <child meets condition>
)
AND <parent meets some condition>

Вариант 3 (на мой взгляд, самый быстрый)

SELECT COUNT(pt.ID)
FROM PARENT_TABLE pt
WHERE EXISTS
(
SELECT 1
FROM CHILD_TABLE ct
WHERE ct.PARENT_ID = pt.ID
AND <child meets condition>
)
AND <parent meets some condition>

Или это что-то совсем другое? Зависит ли это от размеров каждой таблицы, от сложности двух условий или от того, отсортированы ли данные?

РЕДАКТИРОВАТЬ: База данных - это Oracle.


person Yozarian22    schedule 23.09.2011    source источник
comment
Почему бы не провести некоторые тесты производительности на выборке данных соответствующего размера?   -  person a'r    schedule 23.09.2011
comment
В SQL Server 2005 или более поздних версиях параметры 2 и 3 будут обрабатываться одинаково.   -  person JNK    schedule 23.09.2011
comment
Чтобы получить точный ответ, поделитесь своей СУБД.   -  person JNK    schedule 23.09.2011
comment
В Oracle зависит от статистики, но 2 и 3 могут совпадать.   -  person ssedano    schedule 23.09.2011
comment
Догадки ничего не стоят, вы должны посмотреть на фактический план выполнения запроса на достаточно больших выборочных данных. Обратите внимание на использование индексов и несоответствие между фактическим и оценочным количеством извлеченных строк (большие несоответствия говорят о том, что вам нужно создать/обновить статистику по таблицам).   -  person pkmiec    schedule 23.09.2011
comment
+1 к плану выполнения запроса...   -  person    schedule 23.09.2011


Ответы (3)


Первый запрос медленный, остальные должны работать быстро на большинстве БД.

Не зная БД сложно сказать больше:

Но: count(*) часто быстрее, чем count(names_field) и никогда не медленнее
count(distinct (afield)) медленный

Или это что-то совсем другое?

Это зависит от БД и точной версии БД.

Зависит ли это от размеров каждого стола

Да, это играет большую роль

или сложность двух условий

Возможно

или данные сортируются?

Если вам нужен быстрый выбор, все поля, используемые для объединения, должны быть проиндексированы.
И все поля, используемые в предложении where, должны быть либо проиндексированы, либо иметь малое количество элементов.

person Johan    schedule 23.09.2011
comment
+1 - Это в значительной степени подводит итог, насколько вы можете с ограниченной информацией. - person JNK; 23.09.2011
comment
@EvilTeach, не по первичному ключу в контексте внутреннего соединения. - person Johan; 23.09.2011
comment
о да. Это общее предупреждение. - person EvilTeach; 23.09.2011

Для меня первый вариант кажется лучшим, так как его легче всего читать, но это, очевидно, не отвечает на ваш вопрос.

Что вам действительно нужно сделать, так это создать планы выполнения для каждого из запросов и проанализировать их (я думаю, что в большинстве популярных СУБД есть инструмент для этого). Это даст вам значение стоимости для каждого запроса.

Если вы не можете этого сделать, я думаю, вы можете запускать запросы несколько раз и сравнивать время выполнения.

Или это что-то совсем другое? Зависит ли это от размеров каждой таблицы, от сложности двух условий или от того, отсортированы ли данные?

Все это и многое другое.

person pablochan    schedule 23.09.2011

Как говорят комментаторы, лучший способ ответить на этот вопрос — запустить запросы и измерить.

Однако в целом механизмы баз данных оптимизируют соединения очень и очень эффективно — я почти уверен, что вы не найдете почти никакой разницы между тремя запросами, и вполне возможно, что оптимизаторы запросов превратят их все в один и тот же базовый запрос (2 и 3). эквивалентны как есть).

Безусловно, наибольшее влияние на запрос окажут предложения «дочерний элемент соответствует некоторому условию» и «родительский элемент соответствует некоторому условию». Я бы сосредоточился на оптимизации этого бита.

person Neville Kuyt    schedule 23.09.2011
comment
Не правда. Сравнение IN и DISTINCT ОЧЕНЬ сильно повлияет на время обработки. - person JNK; 23.09.2011
comment
ах да - DISTINCT вообще зло, особенно. с точки зрения производительности. Не заметил этого маленького самородка... Однако я думаю, что пункты where окажут большое влияние - person Neville Kuyt; 23.09.2011