2017-02-03 10 views
1

У меня есть таблица (T1) с ок. 500000 не являющиеся дубликаты записей:Оптимальное объединение в двух таблицах MySQL

ID1 Relation ID2 
4  Rel4  13 
5  Rel5  4 
13  Rel13  16 
16  Rel16  5 

У меня есть свойства таблицы T1_Prop:

ID Entity  
4  Ent4  
5  Ent5 
13 Ent13 
16 Ent16 

Я хочу присоединиться к этим две таблицы (на основе идентификатора: 4) эффективным образом следующим образом:

Entity Relation Entity 
Ent4  Rel4  Ent13 
Ent5  Rel5  EntEnt4 

Я разработал этот оператор select, включая JOIN, который работает нормально. Тем не менее, я не уверен, что это лучший способ:

select 
    a.entity, 
    r.relation, 
    b.entity 
from T1 as r 
INNER JOIN T1_Prop as a ON a.ID=r.ID1 AND (r.ID1=4 OR r.ID2=4) 
INNER JOIN T1_Prop as b ON b.ID=r.ID2; 
+1

Оптимизация вопросов принадлежит http://codereview.stackexchange.com/ – Sirko

+0

Лучшая с точки зрения чего? – Shadow

+0

С точки зрения эффективности.Я просто хочу использовать MySQL как свой, и я не пытаюсь улучшить его с помощью некоторых exernal-библиотек или так. – StaOver

ответ

0

Это прекрасное использование SQL. Он построен для такого рода запросов.

Вам понадобится два индекса покрытия, чтобы ускорить это, на T1. К ним относятся:

(ID1, ID2, relation) 

и

(ID2, ID1, relation) 

два индекса предназначен для обработки положения OR. Это единственная потенциальная проблема производительности, которую я вижу, и только потому, что операции OR иногда обманывают планировщика запросов, делая слишком много сканирования таблицы.

Попробуйте переформулировать свой запрос, чтобы сделать ваш выбор значений идентификатора более заметным.

select a.entity, r.relation, b.entity 
    from T1 as r 
INNER JOIN T1_Prop as a ON a.ID=r.ID1 
INNER JOIN T1_Prop as b ON b.ID=r.ID2 
WHERE (r.ID1=4 OR r.ID2=4) 

Тогда, если у вас есть проблемы с производительностью, после создания индексов покрытия, реорганизовать его снова

select a.entity, r.relation, b.entity 
    from T1 as r 
INNER JOIN T1_Prop as a ON a.ID=r.ID1 
INNER JOIN T1_Prop as b ON b.ID=r.ID2 
WHERE r.ID1=4 
UNION 
select a.entity, r.relation, b.entity 
    from T1 as r 
INNER JOIN T1_Prop as a ON a.ID=r.ID1 
INNER JOIN T1_Prop as b ON b.ID=r.ID2 
WHERE r.ID2=4 
+0

Сделайте это 'UNION ALL', что будет более эффективным, чем ненужное удаление дубликатов по умолчанию. –

0

Ваш запрос выглядит отлично для первого ON пункта, за исключением. Условие (r.ID1=4 OR r.ID2=4) не является правилом, для которого запись от T1_Prop для присоединения к записи T1. Это скорее условие, которое T1 записей, чтобы рассмотреть и принадлежит, следовательно, в статье WHERE.

select 
    a.entity AS entity1, 
    r.relation, 
    b.entity AS entity2 
FROM t1 AS r 
INNER JOIN t1_prop AS a ON a.id = r.id1 
INNER JOIN t1_prop AS b ON b.id = r.id2 
WHERE r.id1 = 4 OR r.id2 = 4; 

Это не изменит план выполнения; СУБД будет выполнять это точно так же. Но это более читаемо, поскольку оно показывает фактическое намерение: получить отношения, когда один из ID равен 4 и присоединиться к сущности к этим отношениям.

Другой вариант, чтобы показать это намерение:

select 
    a.entity AS entity1, 
    r.relation, 
    b.entity AS entity2 
FROM (SELECT * FROM t1 WHERE r.id1 = 4 OR r.id2 = 4) AS r 
INNER JOIN t1_prop AS a ON a.id = r.id1 
INNER JOIN t1_prop AS b ON b.id = r.id2; 

Некоторые считают подзапросы в FROM менее читаемым, но, хорошо, а другие нет. И когда запросы становятся более сложными и говорят, что вы даже имеете дело с агрегатами из разных таблиц, это часто является способом выхода и создания чистого запроса.

Ни один из вышеперечисленных запросов на самом деле не лучше, чем другой.

+0

Подзапрос требует дополнительных усилий. –

+0

@ Рик Джеймс: Что? СУБД должна прийти к одному и тому же плану выполнения двух запросов, если его оптимизатор работает хорошо. Если MySQL еще не существует, все зависит от его текущей реализации, которая могла бы лучше поддерживать первый или второй запрос. Возможно, MySQL имеет проблемы с производными таблицами в текущей версии; Я не знаю. Но даже если это так, в следующей версии может быть иная :-) –

+0

'EXPLAIN SELECT ...' для двух должны сказать, стал ли Оптимизатор более умным. Это _might_ будет чем-то, что улучшилось примерно в 5.7. –