Açık ve örtük SQL birleştirmeleri


399

Açık ve örtük iç birleşmede herhangi bir verimlilik farkı var mı? Örneğin:

SELECT * FROM
table a INNER JOIN table b
ON a.id = b.id;

vs.

SELECT a.*, b.*
FROM table a, table b
WHERE a.id = b.id;

11
İyi soru. Açık birleştirmenin neden kullanıldığını merak ediyorum. Tüm sorguları onsuz yapmak mümkün değil mi?
Andrew

6
her iki sorgu hakkında farkı bilmek için EXPLAIN anahtar kelime kullanın .. JOIN kullanın ve farkı görmek .. 100
k'dan

@andrew Benim sorum aslında örtük birleştirmenin bir tür "hack" olup olmadığıydı ("Birden fazla tablo içeren bir sorgu, bir birleştirmeyi kullanmıyor musunuz? Bu bir kesmek değil mi?")
bobobobo

3
Farklıdırlar, örtük birleşme null değerlerle uğraşırken arada bir sizi şaşırtacaktır; açık birleştirme kullanın ve "hiçbir şey değişmediğinde" ortaya çıkan hatalardan kaçının!
BlackTigerX

1
Fark yok. ,olan CROSS JOINgevşek ve bağlayıcı INNER JOINolan CROSS JOINile ONbenzer WHEREancak bağlayıcı sıkı. Yürütülmesi gereken önemli olan DBMS'nin sorguları nasıl optimize ettiği.
philipxy

Yanıtlar:


132

Performans açısından, bunlar tamamen aynıdır (en azından SQL Server'da).

Not: IMPLICIT OUTER JOINSözdiziminin SQL Server 2005'ten bu yana kullanımdan kaldırıldığını unutmayın. ( IMPLICIT INNER JOINSoruda kullanılan sözdizimi hala desteklenmektedir)

"Eski Tarz" ın Sözdiziminin Kullanımdan Kaldırılması: Sadece Kısmi Bir Şey


4
@lomaxx, sadece netlik adına , sorudaki 2 sözdiziminin hangi sözdiziminin kaldırıldığını belirtebilir misiniz ?
J Wynia

8
Destekleyici belgeler sağlayabilir misiniz? Bu, birden fazla düzeyde yanlış geliyor.
NotMe

21
SQL standardını nasıl kullanıyorsunuz?
David Crawshaw

7
@david Crenshaw, örtük birleştirme artık standartta değil ve 18 yıldır.
HLGEM

11
"İç" veya "çapraz" çeşitliliğin "örtülü birleşimleri" Standartta kalır. SQL Server, daha önce hiç Standart olmayan "eski stil" dış birleştirme sözdizimini (yani *=ve =*) kullanımdan kaldırıyor .
oneday28

129

Şahsen ben tabloların birleştirildiğini ve nasıl birleştirildiklerini daha açık hale getirdiği için birleştirme sözdizimini tercih ederim. 8 farklı tablodan seçtiğiniz büyük SQL sorgularını karşılaştırmayı deneyin ve burada çok fazla filtreleme yapın. Birleştirme sözdizimini kullanarak, tabloların birleştirildiği bölümleri, satırları filtrelediğiniz bölüme ayırırsınız.


4
Tamamen katılıyorum, ama bu bir tür konu dışı. OP verimlilik hakkında sordu.
villasv

56

MySQL 5.1.51'de, her iki sorgu da aynı yürütme planlarına sahiptir:

mysql> explain select * from table1 a inner join table2 b on a.pid = b.pid;
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
| id | select_type | table | type | possible_keys | key  | key_len | ref          | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
|  1 | SIMPLE      | b     | ALL  | PRIMARY       | NULL | NULL    | NULL         |  986 |       |
|  1 | SIMPLE      | a     | ref  | pid           | pid  | 4       | schema.b.pid |   70 |       |
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
2 rows in set (0.02 sec)

mysql> explain select * from table1 a, table2 b where a.pid = b.pid;
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
| id | select_type | table | type | possible_keys | key  | key_len | ref          | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
|  1 | SIMPLE      | b     | ALL  | PRIMARY       | NULL | NULL    | NULL         |  986 |       |
|  1 | SIMPLE      | a     | ref  | pid           | pid  | 4       | schema.b.pid |   70 |       |
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
2 rows in set (0.00 sec)

table1166208 satıra sahiptir; table2yaklaşık 1000 satırı vardır.

Bu çok basit bir durum; hiçbir şekilde sorgu optimize edicinin kafası karışmayacağını ve daha karmaşık bir durumda farklı planlar üreteceğini kanıtlamaz.


Bu kabul edilen cevap olmalı. Bu doğrudur, plan aynıdır (veya daha büyük ifadelere yakındır), ancak kayıtların sayısı sert olacaktır, bu nedenle performansta fark yaratacaktır.
SovietFrontier

37

İkinci sözdiziminin istenmeyen bir birleştirme olasılığı vardır: karşılık gelen WHERE deyimi olmadan FROM kısmına tablolar ekleyebilirsiniz. Bu zararlı olarak kabul edilir.


From yan tümcesindeki tablo adları where yan tümcesinde kullanılan tablolardan oluşturulursa ne olur?
Jus12

açık JOIN sözdizimi ile de çapraz birleştirme yapabilirsiniz. ( stackoverflow.com/a/44438026/929164 ) muhtemelen daha az katı, dolayısıyla kullanıcı hatasına daha yatkın olduğunu kastediyorsunuz.
Daniel Dubovski

15

Verdiğiniz ilk cevap ANSI birleştirme sözdizimi olarak bilinir, diğeri geçerlidir ve herhangi bir ilişkisel veritabanında çalışacaktır.

Grom ile ANSI birleştirme sözdizimi kullanmanız gerektiğini kabul ediyorum. Dedikleri gibi, ana sebep açıklıktır. Birçoğu tabloları ve bazıları ANSI birleştirme sözdizimi ile döndürülen satırları kısıtlayan birçok tahmin içeren bir nerede cümlesine sahip olmak yerine, tablolarınıza katılmak için hangi koşulların kullanıldığını ve Sonuçlar.


5

Performans açısından, bunlar tamamen aynıdır (en azından SQL Server'da), ancak bu birleştirme sözdizimini kullanımdan kaldırdıklarını ve kutunun dışında sql server2005 tarafından desteklenmediklerini unutmayın.

Sanırım kullanımdan kaldırılmış * = ve = * operatörlerini ve "dış birleşimi" düşünüyorsunuz.

Şimdi verilen iki formatı test ettim ve bir SQL Server 2008 veritabanında düzgün çalışıyorlar. Benim durumumda aynı yürütme planları verdiler, ancak bunun her zaman doğru olacağını güvenle söyleyemedim.


5

@lomaxx: Açıklığa kavuşturmak için yukarıdaki sözdiziminin ikisinin de SQL Serv 2005 tarafından desteklendiğinden eminim. Aşağıdaki sözdizimi desteklenmiyor ancak

select a.*, b.*  
from table a, table b  
where a.id *= b.id;

Özellikle, dış birleştirme (* =) desteklenmez.


2
Açıkçası SQL Server 2000'de bile kullanmazdım, * = sözdizimi genellikle yanlış cevaplar verir. Bazen bunları çapraz birleşimler olarak yorumlar.
HLGEM

2

Bazı veritabanlarında (özellikle Oracle) birleştirmelerin sırası, sorgu performansını (ikiden fazla tablo varsa) büyük bir fark yaratabilir. Bir uygulamada, bazı durumlarda tam anlamıyla iki büyüklük farkı siparişimiz vardı. İç birleşim sözdizimini kullanmak, bunun üzerinde denetim sağlar - doğru ipuçları sözdizimini kullanırsanız.

Hangi veritabanını kullandığınızı belirtmediniz, ancak olasılık gerçek bir fark yaratmadığı yerlerde SQL Server veya MySQL'i önerir.


1
Leigh, ipuçlarını örtülü birleşimlerde de kullanabilirsiniz.
SquareCog

1
Oracle'da, birleştirme emrinin yürütme planını anlamlı bir şekilde etkilemesi son derece nadirdir. Açıklama için Jonathan Lewis'in bu makalesine bakın .
Jon Heller

1

Leigh Caldwell'in belirttiği gibi, sorgu optimize edici, aynı SQL ifadesine işlevsel olarak neye benzediğine bağlı olarak farklı sorgu planları üretebilir. Bu konuyla ilgili daha fazla bilgi için aşağıdaki iki blog gönderisine bir göz atın:

Oracle Optimizer Ekibinden bir gönderi

"Yapısal Veri" blogundan başka bir yayın

Umarım bunu ilginç bulursun.


Mike, bahsettikleri fark, açık bir birleştirme belirtirseniz , filtreye değil, katılmak için birleştirme koşulunu belirttiğinizden emin olmanız gerektiğidir . Anlamsal olarak doğru sorgular için yürütme planının aynı olduğunu göreceksiniz.
SquareCog

1

Performans açısından, herhangi bir fark yaratmamalıdır. Açık birleştirme sözdizimi, from yan tümcesindeki tablolar arasındaki ilişkileri açıkça tanımladığı ve where yan tümcesini karıştırmayacağı için bana daha temiz görünüyor.


0

Temel olarak, ikisi arasındaki fark, birinin eski şekilde yazılması, diğerinin modern şekilde yazılmasıdır. Şahsen, iç, sol, dış, sağ tanımları kullanarak modern komut dosyasını tercih ediyorum çünkü daha açıklayıcı ve kodu daha okunabilir hale getiriyor.

İç birleşimlerle uğraşırken okunabilirlikte gerçek bir fark yoktur, ancak eski yöntemde olduğu gibi sol ve sağ birleşimlerle uğraşırken karmaşıklaşmayabilir:

SELECT * 
FROM table a, table b
WHERE a.id = b.id (+);

Yukarıdakilerin aksine sol birleştirmenin nasıl yazıldığının eski yolu:

SELECT * 
FROM table a 
LEFT JOIN table b ON a.id = b.id;

Gördüğünüz gibi, betiğin nasıl yazıldığının modern yolu sorguyu daha okunabilir hale getirir. (Bu arada sağ bağlantılar için ve dış bağlantılar için biraz daha karmaşık).

Kazan plakasına geri dönersek, SQL derleyicisinde sorguyu aynı şekilde ele alırken nasıl yazıldığını fark etmez. Oracle veritabanlarında, hem yaşlı hem de genç birçok insanın yazdığı bir karışım gördüm. Yine, senaryonun ne kadar okunabilir olduğuna ve birlikte geliştirdiğiniz takıma bağlıdır.


-1

Deneyimlerime göre, nerede-bir-nerede-ile-yan tümce sözdizimi kullanmak, özellikle bir Microsoft SQL ürünü kullanıyorsanız, genellikle beyin hasarlı bir yürütme planı oluşturur. Örneğin, SQL Server'ın tablo satırı sayılarını tahmin etmeye çalışma biçimi vahşice korkunçtur. İç birleştirme sözdiziminin kullanılması, sorgunun nasıl yürütüldüğü konusunda size bazı kontroller verir. Bu yüzden pratik bir bakış açısından, mevcut veritabanı teknolojisinin atavistik doğası göz önüne alındığında, iç birleşime gitmek zorundasınız.


5
Bunun bir kanıtı var mı? Çünkü kabul edilen cevap aksini söylüyor.
cimmanon
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.