Почему стандарт SQL ANSI-92 лучше не принят ANSI-89?

В каждой компании, в которой я работал, я обнаружил, что люди все еще пишут свои SQL-запросы в стандарте ANSI-89:

select a.id, b.id, b.address_1
from person a, address b
where a.id = b.id

а не стандарт ANSI-92:

select a.id, b.id, b.address_1
from person a
inner join address b
on a.id = b.id

Для такого чрезвычайно простого запроса, как этот, нет большой разницы в удобочитаемости, но для больших запросов я нахожу, что объединение моих критериев объединения с перечислением таблицы значительно упрощает поиск возможных проблем в моем объединении, и позвольте мне сохранить всю фильтрацию в предложении WHERE. Не говоря уже о том, что я чувствую, что внешние объединения намного более интуитивны, чем синтаксис (+) в Oracle.

Когда я пытаюсь пропагандировать ANSI-92 для людей, есть ли какие-то конкретные преимущества в производительности при использовании ANSI-92 по сравнению с ANSI-89? Я бы попробовал это сам, но настройки Oracle, которые мы здесь имеем, не позволяют нам использовать EXPLAIN PLAN - не хотелось бы, чтобы люди пытались оптимизировать свой код, не так ли?

16 ответов

Решение

Согласно "Настройка производительности SQL" Питера Гулутзана и Труди Пельцер, из шести или восьми брендов RDBMS, которые они тестировали, не было никакой разницы в оптимизации или производительности соединений SQL-89 по сравнению с соединениями в стиле SQL-92. Можно предположить, что большинство механизмов СУБД преобразуют синтаксис во внутреннее представление перед оптимизацией или выполнением запроса, поэтому синтаксис, читаемый человеком, не имеет значения.

Я также пытаюсь проповедовать синтаксис SQL-92. Спустя шестнадцать лет после того, как это было одобрено, пришло время людям начать использовать это! И все бренды базы данных SQL теперь поддерживают его, поэтому нет никаких оснований продолжать использовать отвратительный (+) Синтаксис Oracle или *= Синтаксис Microsoft/Sybase.

Что касается того, почему так трудно нарушить сообщество разработчиков привычки SQL-89, я могу только предположить, что существует большая "основа пирамиды" программистов, которые кодируют путем копирования и вставки, используя древние примеры из книг, журнальных статей, или другая база кода, и эти люди не изучают новый синтаксис абстрактно. Некоторые люди сопоставляют образцы, а некоторые учатся наизусть.

Однако постепенно я вижу людей, использующих синтаксис SQL-92 чаще, чем раньше. Я отвечаю на вопросы по SQL онлайн с 1994 года.

Ну, стандарт ANSI092 включает в себя довольно отвратительный синтаксис. Естественные объединения - это одно, а пункт ИСПОЛЬЗОВАНИЕ - другое. ИМХО, добавление столбца в таблицу не должно нарушать код, но НАТУРАЛЬНОЕ СОЕДИНЕНИЕ прерывается самым вопиющим образом. "Лучший" способ - это ошибка компиляции. Например, если вы SELECT * где-то, добавление столбца может не скомпилироваться. Следующим лучшим способом сбоя будет ошибка времени выполнения. Это хуже, потому что ваши пользователи могут видеть это, но это все равно дает вам хорошее предупреждение, что вы что-то сломали. Если вы используете ANSI92 и пишете запросы с естественными объединениями, он не будет прерываться во время компиляции и не будет прерываться во время выполнения, запрос просто внезапно начнет давать неправильные результаты. Эти типы ошибок коварны. Отчеты идут неправильно, возможно, финансовое раскрытие неверно.

Для тех, кто не знаком с NATURAL Joins. Они объединяют две таблицы в каждом имени столбца, которое существует в обеих таблицах. Что действительно здорово, когда у вас есть 4-колоночный ключ, и вы устали его печатать. Проблема возникает, когда в Table1 есть уже существующий столбец с именем DESCRIPTION, и вы добавляете в Table2 новый столбец с именем, о, я не знаю, что-то безобидное, например, mmm, DESCRIPTION, и теперь вы объединяете две таблицы в VARCHAR2. (1000) поле в свободной форме.

Предложение USING может привести к полной неопределенности в дополнение к проблеме, описанной выше. В другом посте SO кто-то показал этот ANSI-92 SQL и попросил помощи в его чтении.

SELECT c.* 
FROM companies AS c 
JOIN users AS u USING(companyid) 
JOIN jobs AS j USING(userid) 
JOIN useraccounts AS us USING(userid) 
WHERE j.jobid = 123

Это совершенно неоднозначно. Я поместил столбец UserID в таблицы Companies и user, и жалоб нет. Что если столбец UserID в компаниях является идентификатором последнего человека, который изменил эту строку?

Я серьезно, может кто-нибудь объяснить, почему такая двусмысленность была необходима? Почему он встроен прямо в стандарт?

Я думаю, что Билл прав, что есть большая база разработчиков, которые копируют / вставляют туда через кодирование. На самом деле, я могу признать, что я вроде как один, когда дело доходит до ANSI-92. Каждый пример, который я когда-либо видел, показывал множественные объединения, вложенные в скобки. Честность, которая в лучшем случае затрудняет выбор таблиц в SQL. Но затем евангелист SQL92 объяснил, что на самом деле навязывает порядок соединения. ИИСУС... все те копировщики, которых я видел, теперь навязывают порядок соединения - работу, которая в 95% случаев лучше оставить оптимизаторам, особенно копировщику.

Томалак понял это правильно, когда сказал:

люди не переходят на новый синтаксис только потому, что он есть

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

На ум приходит несколько причин:

  • люди делают это по привычке
  • люди ленивы и предпочитают присоединения по "старому стилю", потому что они требуют меньше ввода
  • у новичков часто возникают проблемы, связанные с синтаксисом соединения SQL-92
  • люди не переходят на новый синтаксис только потому, что он есть
  • люди не знают о преимуществах нового (если вы хотите так называть) синтаксиса, прежде всего о том, что он позволяет фильтровать таблицу перед выполнением внешнего объединения, а не после него, когда все, что у вас есть, - это предложение WHERE.

Со своей стороны, я делаю все свои соединения в синтаксисе SQL-92 и конвертирую код там, где могу. Это более чистый, более читаемый и мощный способ сделать это. Но трудно убедить кого-то использовать новый стиль, когда он думает, что это причиняет ему боль с точки зрения дополнительной работы при наборе текста без изменения результата запроса.

В ответ на ЕСТЕСТВЕННОЕ СОЕДИНЕНИЕ и ИСПОЛЬЗОВАНИЕ пост выше.

ПОЧЕМУ вы когда-нибудь увидели необходимость их использования - они не были доступны в ANSI-89 и были добавлены для ANSI-92 как то, что я вижу только как ярлык.

Я бы никогда не оставил соединение случайно и всегда указывал таблицу / псевдоним и идентификатор.

Для меня единственный путь - ANSI-92. Он более многословен, и синтаксис не нравится последователям ANSI-89, но он аккуратно отделяет ваши СОЕДИНЕНИЯ от вашего ФИЛЬТРАЦИИ.

Сначала позвольте мне сказать, что в SQL Server синтаксис внешнего соединения (*=) не дает правильных результатов все время. Есть моменты, когда это интерпретируется как перекрестное соединение, а не как внешнее соединение. Так что есть веская причина, чтобы перестать использовать его. И этот синтаксис внешнего соединения является устаревшей функцией и не будет в следующей версии SQL Server после SQL Server 2008. Вы по-прежнему сможете выполнять внутренние объединения, но с какой стати кто-то захочет? Они неясны и намного сложнее поддерживать. Нелегко узнать, что является частью объединения, а что на самом деле является предложением where.

Одна из причин, по которой я считаю, что вам не следует использовать старый синтаксис, заключается в том, что понимание объединений и того, что они делают и чего не делают, является критическим шагом для любого, кто будет писать код SQL. Вы не должны писать какой-либо код SQL без тщательного понимания соединений. Если вы хорошо их понимаете, вы, вероятно, придете к выводу, что синтаксис ANSI-92 более понятен и проще в обслуживании. Я никогда не встречал эксперта по SQL, который не использовал синтаксис ANSI-92 по сравнению со старым синтаксисом.

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

Меня учили ANSI-89 в школе и несколько лет проработал в промышленности. Затем я покинул сказочный мир СУБД на 8 лет. Но потом я вернулся, и этому новому материалу ANSI 92 преподавали. Я изучил синтаксис Join On, и теперь я на самом деле преподаю SQL и рекомендую новый синтаксис JOIN ON.

Но обратная сторона, которую я вижу, это коррелированные подзапросы, кажется, не имеет смысла в свете соединений ANSI 92. Когда информация о присоединении была включена в WHERE, а соответствующие подзапросы "объединялись" в WHERE, все казалось правильным и последовательным. В ANSI 92 критерий объединения таблиц отсутствует в WHERE, а подзапрос "join", синтаксис кажется несовместимым. С другой стороны, попытка "исправить" это несоответствие, вероятно, только усугубит ситуацию.

Я не знаю ответа наверняка.. это религиозная война (альбет в меньшей степени, чем Mac-Pc или другие)

Предполагается, что до недавнего времени Oracle (и, может быть, и другие поставщики) не принимали стандарт ANSI-92 (я думаю, что это было в Oracle v9 или около того) и так, для разработчиков DBA /Db, работающих в компаниях, которые все еще использовали эти версии (или хотели, чтобы код был переносимым между серверами, которые могли бы использовать эти версии, они должны были придерживаться старого стандарта...

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

  • В частности, внешние объединения при наличии предикатов условной фильтрации в столбцах, не связанных с объединением, из таблицы на "внешней" стороне объединения.

У меня был запрос, который был изначально написан для SQL Server 6.5, который не поддерживал синтаксис соединения SQL 92, т.е.

select foo.baz
from foo
  left outer join bar
  on foo.a = bar.a

вместо этого было написано как

select foo.baz
from foo, bar
where foo.a *= bar.a

Запрос был на некоторое время, и соответствующие данные были собраны, чтобы сделать запрос слишком медленным, около 90 секунд, чтобы его завершить. К тому времени, когда возникла эта проблема, мы обновились до SQL Server 7.

После работы с индексами и прочим пасхальным кодированием я изменил синтаксис соединения, чтобы он соответствовал SQL 92. Время запроса сократилось до 3 секунд.

Есть веская причина для переключения.

Перемещено отсюда.

Вот несколько моментов, сравнивающих SQL-89 и SQL-92 и устраняющих некоторые заблуждения в других ответах.

  1. NATURAL JOINS ужасная идея. Они неявные и требуют метаинформации о таблице. Ничто в SQL-92 не требует их использования, поэтому просто игнорируйте их. Они не имеют отношения к этой дискуссии.
  2. USING отличная идея, она имеет два эффекта:
    1. Он производит только один столбец в наборе результатов из equijoin.
    2. Это навязывает здравый и здравый смысл. В SQL-89 у вас были люди, пишущие колонку id на обоих столах. После объединения таблиц это становится неоднозначным и требует явного псевдонима. Кроме того, idВ соединении почти наверняка были разные данные. Если вы присоединяете человека к компании, теперь вы должны использовать псевдоним один id в person_id, и один id в company_idбез которого объединение приведет к появлению двух неоднозначных столбцов. Использование глобального уникального идентификатора для суррогатного ключа таблицы является соглашением, которым стандарт награждает USING,
  3. Синтаксис SQL-89 является неявным CROSS JOIN, CROSS JOIN не уменьшает набор, это неявно увеличивает его. FROM T1,T2 такой же как FROM T1 CROSS JOIN T2, который производит декартово соединение, которое обычно не то, что вы хотите. Наличие избирательности, чтобы уменьшить это удалено до отдаленного WHERE условное означает, что вы чаще допускаете ошибки во время проектирования.
  4. SQL-89 , и SQL-92 явный JOINу них другой приоритет. JOIN имеет более высокий приоритет Хуже того, некоторые базы данных, такие как MySQL, очень долго ошибались., Поэтому смешивать два стиля - плохая идея, и сегодня гораздо более популярным является стиль SQL-92.

Инерция и практичность.

ANSI-92 SQL похож на сенсорный ввод. Каким-то теоретическим образом это может когда-нибудь улучшить все, но я могу печатать намного быстрее, глядя на клавиши четырьмя пальцами. Я должен был бы пойти назад, чтобы идти вперед, без гарантии, что когда-нибудь будет результат.

Написание SQL - это около 10% моей работы. Если мне нужен ANSI-92 SQL для решения проблемы, которую ANSI-89 SQL не может решить, я воспользуюсь ею. (На самом деле я использую его в Access.) Если бы его использование все время помогло бы мне быстрее решить мои существующие проблемы, я бы потратил время на его усвоение. Но я могу использовать ANSI-89 SQL, даже не задумываясь о синтаксисе. Мне платят за решение проблем - размышления о синтаксисе SQL - пустая трата времени и денег моего работодателя.

Когда-нибудь, юный Grasshopper, вы будете защищать использование синтаксиса SQL ANSI-92 от молодых людей, которые считают, что вам следует использовать SQL3 (или что-то еще). И тогда ты поймешь.:-)

Я могу ответить с точки зрения обычного разработчика, зная достаточно SQL, чтобы понимать оба синтаксиса, но все же гуглить точный синтаксис вставки каждый раз, когда мне это нужно...:-P (я не делаю SQL весь день, просто время от времени исправляя некоторые проблемы.)

Ну, на самом деле, я нахожу первую форму более интуитивной, не делая очевидной иерархии между двумя таблицами. Тот факт, что я изучил SQL, возможно, со старыми книгами, показывающими первую форму, вероятно, не помогает...;-)
И первая ссылка, которую я нахожу в поиске sql select в Google (который возвращает в основном французские ответы для меня...), сначала показывает более старую форму (затем объясняет вторую).

Просто намекаю на вопрос "почему"... ^_^ Я должен прочитать хорошую, современную книгу (БД по агностике) по этой теме. Если у кого-то есть предложения...

1) Стандартный способ написать OUTER JOIN, против *= или (+) =

2) ЕСТЕСТВЕННОЕ СОЕДИНЕНИЕ

3) Зависит от движка базы данных, чтобы тенденции ANSI-92 были более оптимальными.

4) Ручная оптимизация:

Допустим, у нас есть следующий синтаксис (ANSI-89):

(1)select * from TABLE_OFFICES to,BIG_TABLE_USERS btu
where to.iduser=tbu.iduser and to.idoffice=1

Это может быть записано как:

(2)select * from TABLE_OFFICES to
inner join BIG_TABLE_USERS btu on to.iduser=tbu.iduser
where to.idoffice=1

Но также как:

(3)select * from TABLE_OFFICES to
inner join BIG_TABLE_USERS btu on to.iduser=tbu.iduser and to.idoffice=1

Все они (1),(2),(3) возвращают один и тот же результат, однако они оптимизируются по-разному, это зависит от механизма базы данных, но большинство из них делают:

  • (1) его решение зависит от механизма базы данных.
  • (2) он объединяет обе таблицы, а затем выполняет фильтрацию для каждого офиса.
  • (3) он фильтрует BIG_TABLE_USERS, используя idoffice, затем объединяет обе таблицы.

5) Более длинные запросы менее беспорядочные.

Причины, по которым люди используют ANSI-89 из моего практического опыта работы со старыми и молодыми программистами, стажерами и новыми выпускниками:

  • Они изучают SQL из существующего кода, который они видят (а не из книг), и изучают ANSI-89 из кода
  • ANSI-89, потому что меньше печатать
  • Они не думают об этом и используют тот или иной стиль и даже не знают, какой из них считается новым или старым, и им все равно
  • Идея о том, что код также является связующим звеном со следующим программистом, поддерживающим код, не существует. Они думают, что разговаривают с компьютером, а компьютеру все равно.
  • Искусство "чистого кодирования" неизвестно
  • Знание языка программирования и SQL, в частности, настолько плохо, что они копируют и вставляют то, что находят в другом месте.
  • Личное предпочтение

Я лично предпочитаю ANSI-92 и изменяю каждый запрос, который я вижу в синтаксисе ANSI-89, иногда только для лучшего понимания оператора SQL под рукой. Но я понял, что большинство людей, с которыми я работаю, не достаточно опытны, чтобы писать объединения во многих таблицах. Они пишут так хорошо, как могут, и используют то, что запомнили, когда впервые столкнулись с оператором SQL.

Я не могу говорить за все школы, но в моем университете, когда мы делали модуль SQL нашего курса, они не учили ANSI-92, они учили ANSI-89 - на старой системе VAX! Я не сталкивался с ANSI-92 до тех пор, пока не начал копаться в Access, создав несколько запросов с помощью конструктора запросов и затем копаясь в коде SQL. Поняв, что я понятия не имею, как он завершает соединения, или каков синтаксис, я начал копать глубже, чтобы понять его.

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

Конечно, есть те технические евангелисты, которые любят повозиться и понять, и, как правило, это те типы, которые принимают "более новые" принципы и пытаются преобразовать все остальное.

Как ни странно, мне кажется, что многие программисты выходят из школы и перестают развиваться; думая, что, потому что это то, чему их учили, это то, как это делается. Только когда вы уберете свои шоры, вы поймете, что школа предназначена только для того, чтобы научить вас основам и дать вам достаточно понимания, чтобы выучить все остальное самостоятельно, и что на самом деле вы едва поцарапали поверхность того, что нужно знать; Теперь твоя работа - продолжать этот путь.

Конечно, это только мое мнение, основанное на моем опыте.

Oracle не очень хорошо внедряет ANSI-92. У меня было несколько проблем, не в последнюю очередь потому, что таблицы данных в Oracle Apps очень хорошо снабжены столбцами. Если количество столбцов в ваших объединениях превышает примерно 1050 столбцов (что очень легко сделать в приложениях), то вы получите эту ложную ошибку, которая не имеет абсолютно никакого логического смысла:

ORA-01445: cannot select ROWID from a join view without a key-preserved table.

Переписывание запроса с использованием синтаксиса соединений старого стиля устраняет проблему, что, судя по всему, прямо указывает на вину в реализации соединений ANSI-92.

До тех пор, пока я не столкнулся с этой проблемой, я неуклонно продвигал ASNI-92 из-за преимуществ, связанных с уменьшением вероятности случайного перекрестного соединения, что слишком легко сделать с помощью синтаксиса старого стиля.

Однако сейчас мне гораздо сложнее на этом настаивать. Они указывают на плохую реализацию Oracle и говорят: "Мы сделаем это по-своему, спасибо".

Новый стандарт SQL наследует все от предыдущего стандарта, иначе говоря, "оковы совместимости". Таким образом, "старый" / "разделенный запятыми" / "неквалифицированный" стиль соединения является совершенно допустимым синтаксисом SQL-92.

Теперь я утверждаю, что SQL-92 NATURAL JOIN это единственное присоединение, которое вам нужно. Например, я утверждаю, что это лучше, чем inner join потому что он не генерирует повторяющиеся столбцы - больше нет переменных диапазона в SELECT пункты для устранения неоднозначности столбцов! Но я не могу рассчитывать на то, что смогу изменить каждое сердце и ум, поэтому мне нужно поработать с программистами, которые будут продолжать применять то, что я лично считаю устаревшими стилями соединения (и они могут даже называть переменные диапазона "псевдонимами"!). Это характер командной работы, а не работа в вакууме.

Одна из критических замечаний языка SQL заключается в том, что тот же результат может быть получен с использованием ряда семантически эквивалентных синтаксисов (некоторые используют реляционную алгебру, некоторые используют реляционное исчисление), где выбор "лучшего" просто сводится к личному стилю, Так что я так же комфортно с соединениями в "старом стиле", как и с INNER, Буду ли я уделить время, чтобы переписать их как NATURAL зависит от контекста.

Другие вопросы по тегам