2014-12-29 3 views
2

Моя конечная цель ... SELECT все поля из qry1 по строкам, где или домашний телефон, мобильный телефон, или работа матч телефон tbl2Как выполнить JOIN, если выполнено одно из нескольких условий?

Это мой текущий синтаксис SQL, который «не удается.» По ошибке я имею в виду, что он не закончил выполнение через 10-15 минут, в то время как каждый человек присоединяется к каждому (независимо) через минуту или две части.

SELECT qry1.* FROM qry1 INNER JOIN tbl2 ON ((qry1.CellPhone = tbl2.CellPhone) OR (qry1.HomePhone = tbl2.HomePhone) OR (qry1.WorkPhone = tbl2.WorkPhone));

Вопросы: Существуют ли ошибки в моем синтаксисе SQL? Есть ли лучший способ выполнить мою задачу? Будет ли для меня больше смысла просто запускать 3 (Home, work, cell) JOIN запросы независимо, UNION их, а затем дедупировать, если необходимо?

+0

В вашем синтаксисе SQL нет ошибок; запрос не будет выполняться, если бы они были. Насколько велики, грубо говоря, таблицы? Сколько строк в каждом и типичный размер строки. И примерно, сколько строк в результирующем наборе?Это в основном любопытство - но 1-2 минуты за отдельный запрос предполагает, что таблицы должны быть довольно большими. –

+0

В Excel (формат xlsx) большая таблица, загружающая qry1, составляет 80 МБ, tbl2 - 50 МБ. tbl2 ужасно широк. – ChrisG

ответ

5

Если отдельные соединения работают быстро, составное условие ИЛИ, вероятно, медленное, потому что оно не может использовать один индекс, тогда как индивидуальные условия могут использовать один индекс для трех условий соединения. Поскольку он не может использовать один индекс, он, вероятно, делает неиндексированные последовательные сканирование таблицы. (Вы должны изучить план запроса, чтобы вы понимали, что делает оптимизатор.)

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

SELECT qry1.* FROM qry1 INNER JOIN tbl2 ON qry1.CellPhone = tbl2.CellPhone 
UNION 
SELECT qry1.* FROM qry1 INNER JOIN tbl2 ON qry1.HomePhone = tbl2.HomePhone 
UNION 
SELECT qry1.* FROM qry1 INNER JOIN tbl2 ON qry1.WorkPhone = tbl2.WorkPhone 

Это должно дать вам результат примерно так же быстро, как и три отдельных запроса. Это будет не так быстро, потому что UNION делает дублирование элиминации (что, разумеется, не требует индивидуальных запросов). Вы можете использовать UNION ALL, но если в двух таблицах есть много строк, где совпадают две или три пары полей, это может привести к большому количеству повторений в результатах.

+0

Работал красиво, спасибо. – ChrisG

+1

Я также хотел бы добавить, что ваше использование 'UNION' для дублирования было именно тем, что мне было нужно. – ChrisG

2

or может быть довольно сложным для оптимизаторов SQL. Я хотел бы предложить 3 индексы и folllowing запрос:

SELECT qry1.* 
FROM qry1 
WHERE EXISTS (SELECT 1 FROM tbl2 WHERE qry1.CellPhone = tbl2.CellPhone) OR 
     EXISTS (SELECT 1 FROM tbl2 WHERE qry1.HomePhone = tbl2.HomePhone) OR 
     EXISTS (SELECT 1 FROM tbl2 WHERE qry1.WorkPhone = tbl2.WorkPhone); 

Три индексы tbl2(CellPhone), tbl2(HomePhone) и tbl2(WorkPhone).

+0

Я думаю, что 'SELECT NULL ...' легче других фиктивных 'SELECT'-s. Раньше я использовал 'SELECT *' для подзапросов EXISTS, но затем видел некоторые примеры с 'NULL'. Не уверен, что мой способ лучше ... – i486

+0

Этот код был медленным, потому что я не создал правильные индексы. Моя вина. – ChrisG

+0

@ i486: Любой сторонний оптимизатор запросов игнорирует список выбора в подзапросе EXISTS; неважно, будете ли вы писать '*', '1',' NULL' или что-то еще. –

0

следующее похоже на https://stackoverflow.com/a/27696729/4350148, но использует несвязанный союз. Может быть более эффективным

SELECT qry1.* FROM qry1 INNER JOIN tbl2 ON qry1.CellPhone = tbl2.CellPhone 
UNION distinct 
SELECT qry1.* FROM qry1 INNER JOIN tbl2 ON 
    qry1.CellPhone != tbl2.CellPhone 
    and qry1.HomePhone = tbl2.HomePhone 
UNION distinct 
SELECT qry1.* FROM qry1 INNER JOIN tbl2 ON 
    qry1.CellPhone != tbl2.CellPhone 
    and qry1.HomePhone != tbl2.HomePhone 
    and qry1.WorkPhone = tbl2.WorkPhone 
1

Если это по существу само соединение, где существуют одни и те же люди, как в tbl1 и QRY1, то вы, вероятно, не будет интересно, где люди померяться, а также повторяющиеся перестановки результатов , То, что я имею в виду, само присоединяется обычно имеют две записи, где Боб и Джейн имеют один и тот же номер телефона, и, таким образом, ваш результат объединил записи о:

Bob, Jane 
Jane, Bob 
Jane, Jane 
Bob, Bob 

Из них вы, вероятно, нужно только Bob, Jane, так как это говорит о том, что эти два человека имеют соответствующий номер телефона. Если у вас есть уникальный идентификатор, то добавление where qry1.SSN < tbl2.SNN устранит многие из этих дубликатов и уменьшит ваш набор результатов. Предпочтительно, чтобы этот столбец имел индекс.

+0

В этой конкретной ситуации ваш ответ/комментарий на самом деле не применялся, но я знаю, что в будущем я столкнусь с чем-то очень похожим на это. Благодаря! – ChrisG