Вопрос

Я только что научился (вчера) использовать " существующие " вместо "в".

 BAD
 select * from table where nameid in ( 
          select nameid from othertable where otherdesc =  'SomeDesc' )      
 GOOD
 select * from table t where exists ( 
          select nameid from othertable o where t.nameid = o.nameid and otherdesc =  'SomeDesc' )      

И у меня есть несколько вопросов по этому поводу:

1) Я понял следующее объяснение: " причина, по которой это лучше, заключается в том, что вместо создания массивного списка возможных результатов будут возвращаться только совпадающие значения " . Означает ли это, что если первый подзапрос может вернуть 900 результатов, второй вернет только 1 (да или нет)?

2) В прошлом мне приходилось жаловаться на СУБД: «можно извлечь только первые 1000 строк», этот второй подход решил бы эту проблему?

3) Какова область псевдонима во втором подзапросе? ... псевдоним существует только в скобках?

например

 select * from table t where exists ( 
          select nameid from othertable o where t.nameid = o.nameid and otherdesc =  'SomeDesc' )      
 AND 
          select nameid from othertable o where t.nameid = o.nameid and otherdesc =  'SomeOtherDesc' )      

То есть, если я использую тот же псевдоним (o для таблицы othertable) Во втором " Существуют " это будет представлять какие-либо проблемы с первым существует? или они полностью независимы?

Это что-то, что связано только с Oracle, или оно действительно для большинства СУБД?

Большое спасибо

Это было полезно?

Решение

Это специфично для каждой СУБД и зависит от оптимизатора запросов. Некоторые оптимизаторы обнаруживают предложение IN и переводят его.

Во всех протестированных СУБД псевдоним действителен только внутри ()

Кстати, вы можете переписать запрос как:

select t.* 
from table t 
join othertable o on t.nameid = o.nameid 
    and o.otherdesc in ('SomeDesc','SomeOtherDesc');

И, чтобы ответить на ваши вопросы:

<Ол>
  • Да
  • Да
  • Да
  • Другие советы

    Вы вступаете на сложную территорию, известную как «коррелированные подзапросы». Поскольку у нас нет подробной информации о ваших таблицах и ключевых структурах, некоторые ответы могут быть только «возможно».

    В вашем начальном запросе IN нотация будет действительной независимо от того, содержит ли OtherTable столбец NameID (и, действительно, существует ли OtherDesc в виде столбца в таблице или OtherTable - что непонятно ни в одном из ваших примеров, но предположительно столбец OtherTable). Именно это поведение делает коррелированный подзапрос в коррелированный подзапрос. Это также обычный источник беспокойства для людей, когда они впервые сталкиваются с ним - неизменно случайно. Поскольку стандарт SQL предписывает поведение интерпретации имени в подзапросе как обращения к столбцу во внешнем запросе, если в таблицах, упомянутых в подзапросе, нет столбца с соответствующим именем, но имеется столбец с соответствующее имя в таблицах, упомянутых во внешнем (главном) запросе, ни один продукт, который хочет заявить о соответствии (этой части) стандарту SQL, не сделает ничего другого.

    Ответ на ваш Q1 - «это зависит», но с учетом вероятных предположений (NameID существует в виде столбца в обеих таблицах; OtherDesc существует только в OtherTable), результаты должны быть одинаковыми с точки зрения возвращенного набора данных, но не может быть эквивалентным с точки зрения производительности.

    Ответ на ваш вопрос Q2 заключается в том, что в прошлом вы использовали низшую, если не дефектную СУБД. Если он поддерживает EXISTS, то СУБД может по-прежнему жаловаться на количество результатов.

    Ответ на ваш Q3 применительно к первому запросу EXISTS: «Доступен в качестве псевдонима для всего оператора, но o доступен только в качестве псевдонима в скобках». Применительно к вашему второму примерному блоку - с AND, соединяющим два вложенных элемента выбора (второй из которых пропускает открытые скобки, когда я смотрю на него), тогда " t доступен как псевдоним во всем утверждении и относится к та же таблица, но есть два разных псевдонима, оба помечены как «o», по одному для каждого подзапроса » Обратите внимание, что запрос может не возвращать данные, если OtherDesc уникален для данного значения NameID в OtherTable; в противном случае требуются две строки в OtherTable с одинаковым NameID и два значения OtherDesc для каждой строки в таблице с этим значением NameID.

    <Ол>
  • Специфично для Oracle: когда вы пишете запрос с использованием предложения IN, вы сообщаете оптимизатору на основе правил, что внутренний запрос должен запускать внешний запрос. Когда вы пишете EXISTS в предложении where, вы сообщаете оптимизатору, что вы хотите, чтобы внешний запрос выполнялся первым, используя каждое значение для извлечения значения из внутреннего запроса. См. " Разница между IN и EXISTS в подзапросах " .
  • Возможно.
  • Псевдоним, объявленный внутри подзапроса, живет внутри подзапроса. Кстати, я не думаю, что ваш пример с 2 подзапросами ANDed является допустимым SQL. Вы имели в виду UNION вместо AND?
  • Лично я бы использовал для этого соединение, а не подзапрос.

    SELECT t.*
    FROM yourTable t
        INNER JOIN otherTable ot
            ON (t.nameid = ot.nameid AND ot.otherdesc = 'SomeDesc')
    

    Трудно обобщить, что EXISTS всегда лучше, чем IN. Логично, что в этом случае сообщество SQL заменило бы IN на EXISTS ... Кроме того, обратите внимание, что IN и EXISTS не одинаковы, результаты могут отличаться при использовании двух ...

    С IN, обычно это полное сканирование внутренней таблицы один раз без удаления NULL (поэтому, если у вас есть NULL во внутренней таблице, IN не будет удалять NULLS по умолчанию) ... В то время как EXISTS удаляет NULL и в случае коррелированный подзапрос, он запускает внутренний запрос для каждой строки из внешнего запроса.

    Если предположить, что NULLS отсутствует и это простой запрос (без корреляции), EXIST может работать лучше, если найденная строка не является последней строкой. Если это последняя строка, EXISTS, возможно, придется сканировать до конца, как IN .. так что похожая производительность ...

    Но IN и EXISTS не являются взаимозаменяемыми ...

    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top