SQL оставил соединение по сравнению с несколькими таблицами на ОТ строки?

Этот пример - использовать Reduce (), но замедляет его:

def makepnl(pnl, n):
    for p in pnl:
        if n % p == 0:
            return pnl
    pnl.append(n)
    return pnl

def isprime(n):
    return True if n == reduce(makepnl, range(3, n + 1, 2), [2])[-1] else False

for i in range(20):
    print i, isprime(i)

Он использует Сито Аткина , быстрее чем выше:

def atkin(limit):
    if limit > 2:
        yield 2
    if limit > 3:
        yield 3

    import math
    is_prime = [False] * (limit + 1)

    for x in range(1,int(math.sqrt(limit))+1):
        for y in range(1,int(math.sqrt(limit))+1):
            n = 4*x**2 + y**2

            if n<=limit and (n%12==1 or n%12==5):
                # print "1st if"                                                                                                                    
                is_prime[n] = not is_prime[n]
            n = 3*x**2+y**2
            if n<= limit and n%12==7:
                # print "Second if"                                                                                                                 
                is_prime[n] = not is_prime[n]
            n = 3*x**2 - y**2
            if x>y and n<=limit and n%12==11:
                # print "third if"                                                                                                                  
                is_prime[n] = not is_prime[n]

    for n in range(5,int(math.sqrt(limit))):
        if is_prime[n]:
            for k in range(n**2,limit+1,n**2):
                is_prime[k] = False

    for n in range(5,limit):
        if is_prime[n]: yield n

def isprime(n):
    r = list(atkin(n+1))
    if not r: return False
    return True if n == r[-1] else False

for i in range(20):
    print i, isprime(i)

245
задан Kev 28 May 2011 в 02:11
поделиться

10 ответов

Старый синтаксис, только с перечислением таблиц и используя предложение WHERE , чтобы указать критерии соединения, устарела в большинстве современных баз данных.

Это не просто для показа, старый синтаксис может быть двусмысленным, когда вы используете как INNER, так и OUTER соединения в одном запросе.

Позвольте мне привести вам пример.

Предположим, у вас есть 3 таблицы в вашей системе:

Company
Department
Employee

Каждая таблица содержит множество строк, связанных вместе. У вас несколько компаний, и в каждой компании может быть несколько отделов, и в каждом отделе может быть несколько сотрудников.

Хорошо, теперь вы хотите сделать следующее:

Составьте список всех компаний, включая все их отделы, и все их сотрудники. Обратите внимание, что в некоторых компаниях еще нет отделов, но не забудьте включить их. Убедитесь, что вы извлекаете только отделы, в которых есть сотрудники, но всегда указываете все компании.

Итак, вы делаете следующее:

SELECT * -- for simplicity
FROM Company, Department, Employee
WHERE Company.ID *= Department.CompanyID
  AND Department.ID = Employee.DepartmentID

Обратите внимание, что последнее - это внутреннее соединение, чтобы выполнить критерий, согласно которому вам нужны только отделы с людьми.

Хорошо, что же теперь происходит. Проблема в том, что это зависит от движка базы данных, оптимизатора запросов, индексов и статистики таблиц. Позвольте мне объяснить.

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

Причина в том, что предложение WHERE определяет, какие строки попадают в окончательный результат, а не отдельные части строк.

И в этом случае из-за левого соединения столбец Department.ID будет NULL, и, таким образом, когда дело доходит до INNER JOIN to Employee, там ' s невозможно выполнить это ограничение для строки Employee, и поэтому оно не появится.

С другой стороны, если оптимизатор запросов решит сначала выполнить соединение отдел-сотрудник, а затем выполнить левое соединение с компаний, вы их увидите.

Итак, старый синтаксис неоднозначен. Невозможно указать, что вы хотите, без подсказок запроса, а некоторые базы данных вообще не имеют возможности.

Введите новый синтаксис, вы можете выбрать его.

Например, если вы хотите, чтобы все компании, как указано в описании проблемы, вы должны написать следующее:

SELECT *
FROM Company
     LEFT JOIN (
         Department INNER JOIN Employee ON Department.ID = Employee.DepartmentID
     ) ON Company.ID = Department.CompanyID

Здесь вы указываете, что хотите, чтобы соединение отдел-сотрудник выполнялось как одно соединение, а затем оставьте соединение результатов этого с компаниями.

Дополнительно , допустим, вам нужны только отделы, в названии которых есть буква X. Опять же, со старым стилем, вы также рискуете потерять компанию, если у нее нет отделов с X в названии, но с новым синтаксисом вы можете сделать это:

SELECT *
FROM Company
     LEFT JOIN (
         Department INNER JOIN Employee ON Department.ID = Employee.DepartmentID
     ) ON Company.ID = Department.CompanyID AND Department.Name LIKE '%X%'

Это дополнительное предложение используется для присоединения, но не фильтр для всей строки. Таким образом, строка может отображаться с информацией о компании, но может содержать NULL во всех столбцах отделов и сотрудников для этой строки, потому что для этой компании нет отдела с X в названии. Это сложно со старым синтаксисом.

Вот почему, среди других поставщиков, Microsoft исключила старый синтаксис внешнего соединения, но не старый синтаксис внутреннего соединения, начиная с SQL Server 2005 и выше. Единственный способ поговорить с базой данных, работающей на Microsoft SQL Server 2005 или 2008, используя старый синтаксис внешнего соединения, - это установить для этой базы данных режим совместимости 8.0 (он же SQL Server 2000).

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

Итак, у вас есть.

LEFT и INNER JOIN - это волна будущего.

305
ответ дан 23 November 2019 в 03:07
поделиться

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

Кстати, вы также можете выполнить внешнее соединение с первым синтаксисом:

WHERE a.x = b.x(+)

Или

WHERE a.x *= b.x

Или

WHERE a.x = b.x or a.x not in (select x from b)
16
ответ дан 23 November 2019 в 03:07
поделиться

Первый способ - это старый стандарт. Второй метод был представлен в SQL-92, http://en.wikipedia.org/wiki/SQL . Полный стандарт можно увидеть по адресу http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt .

Потребовалось много лет, чтобы компании, работающие с базами данных, приняли SQL- 92.

Итак, причина, по которой предпочтение отдается второму методу, - это стандарт SQL в соответствии с комитетом по стандартам ANSI и ISO.

11
ответ дан 23 November 2019 в 03:07
поделиться

Второй вариант предпочтительнее, потому что он гораздо менее вероятно приведет к случайному перекрестному соединению из-за того, что вы забудете вставить предложение where. Соединение без предложения on приведет к сбою проверки синтаксиса, соединение в старом стиле с предложением no where не даст сбоя, оно выполнит перекрестное соединение.

Кроме того, когда вам позже потребуется левое соединение, это полезно для обслуживания, которое все они находятся в одной структуре. А старый синтаксис устарел с 1992 года, давно пора перестать его использовать.

9
ответ дан 23 November 2019 в 03:07
поделиться

SELECT * FROM table1, table2, ... синтаксис подходит для пары таблиц, но становится экспоненциально ( не обязательно математически точным утверждением ) все труднее читать по мере увеличения количества таблиц.

Синтаксис JOIN сложнее написать (в начале), но он явно указывает, какие критерии влияют на какие таблицы. Это значительно усложняет ошибку.

Кроме того, если все соединения являются ВНУТРЕННИМИ, то обе версии эквивалентны. Однако в тот момент, когда у вас есть ВНЕШНЕЕ соединение в любом месте оператора, все становится намного сложнее, и это фактически гарантирует, что то, что вы пишете, не будет запрашивать то, что вы думаете, что написали.

5
ответ дан 23 November 2019 в 03:07
поделиться

Обычно, когда в предложении FROM перечислены таблицы, подобные так:

SELECT * FROM
  tableA, tableB, tableC

результат представляет собой перекрестное произведение всех строк в таблицах A, B, C. Затем вы применяете ограничение ГДЕ tableA.id = tableB.a_id , который выбросит огромное количество строк, затем далее ... И tableB.id = tableC.b_id , и тогда вы должны получить только те строки, которые вы действительно заинтересован.

СУБД знают, как оптимизировать этот SQL, так что разница в производительности при написании этого с использованием JOINs незначительна (если таковая имеется). Использование нотации JOIN делает оператор SQL более читаемым (IMHO, отсутствие объединения превращает оператор в беспорядок). Используя перекрестное произведение, вам необходимо указать критерии соединения в предложении WHERE, и в этом проблема с нотацией. Вы переполняете предложение WHERE такими вещами, как

    tableA.id = tableB.a_id 
AND tableB.id = tableC.b_id 

, которые используются только для ограничения перекрестного произведения. Предложение WHERE должно содержать только ОГРАНИЧЕНИЯ для набора результатов. Если вы смешиваете критерии объединения таблиц с ограничениями набора результатов, вам (и другим) будет труднее читать ваш запрос. Вы обязательно должны использовать JOIN и оставить предложение FROM предложением FROM, а предложение WHERE - предложением WHERE.

11
ответ дан 23 November 2019 в 03:07
поделиться

Если вам нужно внешнее соединение, второй синтаксис не всегда требуется :

Oracle:

SELECT a.foo, b.foo
  FROM a, b
 WHERE a.x = b.x(+)

MSSQLServer (хотя он устарел в версии 2000 г.) / Sybase:

SELECT a.foo, b.foo
  FROM a, b
 WHERE a.x *= b.x

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

2
ответ дан 23 November 2019 в 03:07
поделиться

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

0
ответ дан 23 November 2019 в 03:07
поделиться

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

0
ответ дан 23 November 2019 в 03:07
поделиться

Итак, первый и второй запросы могут давать разные результаты, потому что LEFT JOIN включает все записи из первой таблицы, даже если в правой таблице нет соответствующих записей.

0
ответ дан 23 November 2019 в 03:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: