Sorgular neden çoğu cümlede sütun takma adlarının kullanılmasına izin vermeyecek şekilde ayrıştırılıyor?


16

Bir sorgu yazmaya çalışırken, SQL Server'ın bir sorguyu yürütürken SELECT'leri ayrıştırmadan önce bir sorguda WHERE'leri ayrıştırdığını (zor yoldan) öğrendim.

MSDN dokümanlar genel mantıksal ayrıştırma sırası SEC (böylece "böyle bir nesne [ad]" hataları diğer maddelerin bir sütun diğer adı kullanmaya çalışan ile sonuçlanan) hemen hemen son ayrıştırılır şekildedir söylüyor. Takma adların herhangi bir yerde kullanılmasına izin vermek için bir öneri bile vardı , bu da Microsoft ekibi tarafından düşürüldü ve ANSI standartlarına uyumluluk sorunlarına işaret etti (bu, bu davranışın ANSI standardının bir parçası olduğunu gösteriyor).

Bir programcı olarak (DBA değil), bu davranışı biraz kafa karıştırıcı buldum, çünkü bana göre sütun takma adları (veya en azından sütun takma adları, eğer olsaydı önemli ölçüde daha güçlü hale getirilebilir) amacını büyük ölçüde yendi. diğer adları kullanabileceğiniz tek yer ORDER BY konumunda olduğundan, sorgu yürütmesinde daha önce ayrıştırılmıştır) . Bir programcı olarak, sorguları daha güçlü, kullanışlı ve DRY yapmak için büyük bir fırsatı kaçırıyor gibi görünüyor.

Öyle görünüyor ki, akla yatkın bir konu var gibi görünüyor, o zaman, sütun takma adlarına SELECT ve ORDER BY dışında bir şeyde izin verilmemesi gerektiğine karar vermek için başka nedenler var, ancak bu nedenler nelerdir?

Yanıtlar:


19

özet

Bunun yapılamamasının mantıklı bir nedeni yok , ancak fayda küçük ve hemen anlaşılamayacak bazı tuzaklar var.

Araştırma sonuçları

Biraz araştırma yaptım ve iyi bilgiler buldum. 2012-08-09 17:49 GMT'de güvenilir bir birincil kaynaktan (anonim kalmak isteyen) doğrudan bir alıntıdır:

SQL ilk icat edildiğinde, SELECT yan tümcesinde hiçbir takma adı yoktu. Bu, dil 1986'da ANSI tarafından standartlaştırıldığında düzeltilen ciddi bir eksiklikti.

Dilin "prosedürel olmayan" olması amaçlanmıştır - diğer bir deyişle, nasıl bulunacağını belirtmeden istediğiniz verileri tanımlamak için tasarlanmıştır. Bu nedenle, bildiğim kadarıyla, bir SQL uygulamasının işlemden önce tüm sorguyu ayrıştırmamasının ve takma adların herhangi bir yerde tanımlanmasına ve her yerde kullanılmasına izin vermesinin bir nedeni yoktur. Örneğin, aşağıdaki sorgunun geçerli olmaması için herhangi bir neden göremiyorum:

select name, salary + bonus as pay
from employee
where pay > 100000

Bu makul bir sorgu olduğunu düşünüyorum rağmen, bazı SQL tabanlı sistemler bazı uygulama ile ilgili bir nedenden dolayı takma ad kullanımı kısıtlamaları getirebilir. SQL Server'ın bunu yaptığını duyduğuma şaşırmadım.

SQL-86 standardı ve neden modern DBMS'lerin takma adı yeniden kullanımını desteklemediğini, ancak henüz bu konuda çok fazla zaman bulamadıklarını merak ediyorum. Yeni başlayanlar için, belgeleri nereden alacağımı veya komiteyi tam olarak kimin oluşturduğunu nasıl bulacağımı bilmiyorum. Birisi yardım edebilir mi? Ayrıca SQL Server'ın geldiği orijinal Sybase ürünü hakkında daha fazla bilgi edinmek istiyorum.

Bu araştırmadan ve bazı başka düşüncelerden, diğer cümlelerde takma ad kullanmanın, mümkün olsa da, DBMS üreticileri için diğer dil özelliklerine kıyasla hiç bu kadar yüksek bir öncelik olmadığından şüphelenmeye başladım. Sorgu yazarı tarafından kolayca çözülebilen bir engel o kadar da fazla olmadığından, diğer ilerlemeler üzerinde çaba sarf etmek uygun değildir. Ek olarak, açıkça SQL standardının bir parçası olmadığı için tescilli olacaktır (bununla ilgili daha fazla bilgi edinmek için bekliyorum) ve bu nedenle DBMS'ler arasında SQL uyumluluğunu bozan küçük bir gelişme olacaktır. Karşılaştırma yapmak gerekirse, CROSS APPLY(dış referanslara izin veren türetilmiş bir tablodan başka bir şey değildir) büyük bir değişikliktir, bu arada tescilli diğer şekillerde kolayca gerçekleştirilemeyen inanılmaz ifade gücü sunar.

Diğer Adları Her Yerde Kullanmayla İlgili Sorunlar

SELECT öğelerinin WHERE yan tümcesine konmasına izin verirseniz, yalnızca sorgunun karmaşıklığını (ve dolayısıyla iyi bir yürütme planı bulmanın karmaşıklığını) patlatmakla kalmazsınız, tamamen mantıksız şeyler bulmak mümkündür. Deneyin:

SELECT X + 5 Y FROM MyTable WHERE Y = X

MyTable zaten Y sütununa sahipse, hangisinin WHERE yan tümcesi olduğunu belirtir? Çözüm bir CTE veya türetilmiş bir tablo kullanmaktır, bu da çoğu durumda ekstra maliyete neden olmamakla birlikte aynı nihai sonuca ulaşır. CTE'ler ve türetilmiş tablolar, bir takma adın yalnızca bir kez kullanılmasına izin vererek en azından belirsizliğin çözümlenmesini zorunlu kılar.

Ayrıca, FROM yan tümcesinde takma ad kullanılmaması da mantıklıdır. Bunu yapamazsın:

SELECT
   T3.ID + (SELECT Min(Interval) FROM Intervals WHERE IntName = 'T') CalcID
FROM
   Table1 T
   INNER JOIN Table2 T2
      ON T2.ID = CalcID
   INNER JOIN Table3 T3
      ON T2.ID = T3.ID

Bu, (T2 gizlice bu tablo artır liste olarak sunulmuştur önce, T3 bir değeri ifade anlamda) ve dairesel bir kaynaktır yama görmek zordur. Buna ne dersin:

INSERT dbo.FinalTransaction
SELECT
   newid() FinalTransactionGUID,
   'GUID is: ' + Convert(varchar(50), FinalTransactionGUID) TextGUID,
   T.*
FROM
   dbo.MyTable T

Newid () işlevinin iki kez yürütme planına ekleneceğine ne kadar emin olmak istiyorsunuz, bu iki sütunu tamamen beklenmedik bir şekilde farklı değerler gösteriyor. Yukarıdaki sorgu ne zaman CTE'lerde veya türetilmiş tablolarda N düzeylerinde kullanıldığında. Sorunun tahmin edebileceğinizden daha kötü olduğunu garanti ediyorum. Orada zaten şeyler sadece bir kez veya bir sorgu planında hangi noktada değerlendirilir zaman konusunda ciddi tutarsızlık sorunları ve Microsoft söyledi o düzeltme olmazbazıları sorgu cebirini doğru ifade ettikleri için - beklenmedik sonuçlar alırsa, sorguyu parçalara ayırın. Zincirleme referanslara izin vermek, potansiyel olarak çok uzun bu tür zincirlerle dairesel referansları tespit etmek - bunlar oldukça zor problemlerdir. Paralellik tanıtmak ve yapımında bir kabus var.

Not: Diğer adın WHERE veya GROUP BY içinde kullanılması newid () veya rand () gibi işlevlerle ilgili sorunlarda bir fark yaratmayacaktır.

Yeniden kullanılabilir ifadeler oluşturmanın bir SQL Server yolu

ÇAPRAZ UYGULAMA / DIŞ UYGULAMA, SQL Server'da sorguda başka herhangi bir yerde kullanılabilen ifadeler oluşturmanın bir yoludur (FROM yan tümcesinde daha önce değil):

SELECT
   X.CalcID
FROM
   Table1 T
   INNER JOIN Table3 T3
      ON T.ID = T3.ID
   CROSS APPLY (
      SELECT
         T3.ID + (SELECT Min(Interval) FROM Intervals WHERE IntName = 'T') CalcID
   ) X
   INNER JOIN Table2 T2
      ON T2.ID = X.CalcID

Bu iki şey yapar:

  1. ÇAPRAZ UYGULAMADAKİ tüm ifadelerin bir "ad alanı" (bir tablo diğer adı, burada, X) almasını ve bu ad alanı içinde benzersiz olmasını sağlar.
  2. Her yerde sadece CalcID'in X'den geldiğini değil, aynı zamanda T1 ve T3 tablosuna katılırken neden X'ten bir şey kullanamayacağınızı açıkça ortaya koyuyor, çünkü X henüz tanıtılmadı.

Aslında CROSS UYGULAMAYA oldukça düşkünüm. Benim sadık dostum oldu ve ben her zaman kullanıyorum. Kısmi UNPIVOT'a mı ihtiyacınız var (yerel sözdizimini kullanan bir PIVOT / UNPIVOT veya UNPIVOT / PIVOT gerektirir)? ÇAPRAZ UYGULAMA ile yapılır. Birçok kez yeniden kullanılacak hesaplanmış bir değere mi ihtiyacınız var? Bitti. Bağlı bir sunucu üzerinden çağrılar için yürütme sırasını sıkı bir şekilde zorlamanız mı gerekiyor? Hızda çığlık atan bir iyileştirme ile bitti. Sadece 2 sıraya bölünmüş veya fazladan bir sıraya mı ihtiyacınız var? Bitti.

En azından, DBMS SQL Server 2005 ve sonraki sürümlerde, şikayet için başka bir nedeniniz yok: ÇAPRAZ UYGULAMA, istediğiniz şekilde KURUsunuz.


14

Size kesin nedenleri söyleyemem, ancak tekrarlamayı önlemek için ifadeleri tekrarlamak için, örneğin CTE'leri, alt sorguları, türetilmiş tabloları vb. Kullanmak için geçici çözümler olduğunu söyleyeceğim.

Tekrarlanan bir ifadeye sahip bir sorgu gösterirseniz, ifadenin yalnızca bir kez listelenmesi için bunu nasıl yeniden yazacağınızı gösterebiliriz. Bununla birlikte, bu sadece sorguyu yazma / okumadaki karmaşıklığı azaltır, verimlilik hakkında çok fazla değişiklik yapılması olası değildir. SQL Server genellikle ifadelerin tekrarlandığını tanımak konusunda oldukça iyidir ve bu işi iki kez gerçekleştirmez. Diğer yöne giden istisnalar vardır, ancak verimlilik konusunda yalnızca bu olayı gerçekten gözlemlediğinizde endişelenmelisiniz. Yazdığınız çoğu tekrarlanan ifadenin plandaki tek bir işlemde gerçekten çöktüğünden şüpheleniyorum.

Tüm bunlar, cevabımın bir kısmını bu sorudan da tekrarlayacağım dedi:

/dba/19762/why-is-the-select-clause-listed-first


Joe Celko'nun bir sorgunun standarda göre nasıl işlendiğine dair açıklaması (bunu muhtemelen Celko'nun bir haber grubu postasından alıntıyı çalan kendi aspfaq.com makalemden çaldım):

SELECT'in SQL'de nasıl çalıştığı ... en azından teoride. Gerçek ürünler işleri mümkün olduğunca optimize eder.

FROM yan tümcesinde başlayın ve tüm birleşim yerlerinden, sendikalardan, kavşaklardan ve diğer tablo kurucularının her hangi birinden bir çalışma tablosu oluşturun. AS seçeneği, bu çalışma tablosuna daha sonra içeren sorgunun geri kalanı için kullanmanız gereken bir ad vermenize olanak tanır.

WHERE deyimine gidin ve ölçütleri geçmeyen satırları kaldırın; yani, DOĞRU olarak test edilmez (BİLİNMEYEN ve YANLIŞ reddetme). WHERE deyimi, FROM deyimindeki çalışmaya uygulanır.

İsteğe bağlı GROUP BY deyimine gidin, gruplar oluşturun ve orijinal çalışma tablosunu yeni gruplanmış tabloyla değiştirerek her grubu tek bir satıra indirin. Gruplandırılmış bir tablonun satırları grup özellikleri olmalıdır: (1) bir gruplandırma sütunu (2) grup hakkında bir istatistik (yani toplama işlevleri) (3) bir işlev veya (4) bu üç öğeden oluşan bir ifade.

İsteğe bağlı HAVING yantümcesine gidin ve gruplandırılmış çalışma tablosuna uygulayın; GROUP BY deyimi yoksa, tüm tabloyu bir grup olarak ele alın.

SELECT yantümcesine gidin ve listedeki ifadeleri oluşturun. Bu, SELECT içindeki skaler alt sorguların, fonksiyon çağrılarının ve ifadelerin, diğer tüm maddeler tamamlandıktan sonra yapıldığı anlamına gelir. AS operatörü SELECT listesindeki ifadelere de bir ad verebilir. Bu yeni isimler bir anda ortaya çıkar, ancak WHERE cümlesi uygulandıktan sonra; bunları SELECT listesinde veya WHERE ipucunda kullanamazsınız.

Yuvalanmış sorgu ifadeleri, C, Pascal, Algol vb. Gibi blok yapılandırılmış bir dilden bekleyebileceğiniz olağan kapsam belirleme kurallarına uyar. Yani, en içteki sorgular, içerdikleri sorgulardaki sütunlara ve tablolara başvurabilir.

Bu, bir SELECT öğesinin GROUP BY grubundan daha fazla sütuna sahip olamayacağı anlamına gelir; ancak kesinlikle daha az sütunu olabilir.

Şimdi Celko, standartların önceki sürümlerine ana katkıda bulunanlardan biriydi. WHY?Spekülasyonlar dışında soruya kesin bir cevap alıp alamayacağınızı bilmiyorum . Benim tahminim, gerçek operasyonu listelemek, ayrıştırıcının işlem türünün tam olarak ne olacağını tam olarak bilmesini kolaylaştırıyor. Bir SELECTveya UPDATEveya olabilen 20 masalı bir birleşim düşünün DELETEve bu motorların kodunun başlangıçta dize ayrıştırmanın oldukça maliyetli olduğu günlerde yazıldığını unutmayın.

FROMİlk önce dikte edilen SQL standardı , satıcıların bağımsız olarak dilbilgisini farklı bir sırayla ayrıştırmaya karar vermiş olabileceğini unutmayın, bu nedenle yazılı cümlelerin sırasının% 100'ünün işleme sırasına tamamen uymasını beklemek yine de mantıklı olmayabilir. zaman.

Aynı şey gibi şeyler için de geçerlidir CASE. Örneğin, bu sitede , CASEher zaman düzenli ve kısa devrelerde işleyen daha önce inandığı mitin yanlış olduğu senaryoları burada gördük . Ve bu, SQL Server'ın birleşimleri yazıldıkları sırada değerlendirmesi , soldan sağa kısa devre WHEREyan tümceleri veya birden çok kez başvurulsalar bile CTE'leri bir kez veya belirli bir sırada işlemesi gibi diğer yaygın inançlara da uzanır . Ürünler, sorgunun bildirimsel olarak nasıl çalışması gerektiğini belirttiğinizi tam olarak yansıtmasa bile, uygun gördüklerini optimize etmekte serbesttir.


2
Ayrıca, sorgunun farklı bölümlerinde takma ad kullanma veya kullanma yeteneğinin, iyileştirici veya yürütme motoru tarafından değil ayrıştırıcı tarafından uygulandığını unutmayın. Motorun sorguyu gerçekte nasıl yürüttüğü, sözdizimini etkileyen kısıtlamaları yansıtmayabilir.
Aaron Bertrand

2

In Varlık SQL , bazı durumlarda sorguda başka yerlerde ifadelerden adlar kullanın CAN:

select k1, count(t.a), sum(t.a)
from T as t
group by t.b + t.c as k1

Burada, GROUP BYcümlede kullanmak için deyimdeki ifadeyi tanımlamanız GEREKİR SELECT.

Açıkçası olan olası takma-as-yeniden-ifadesi SQL sorguları bu tür bazı izin vermek.

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.