Bu gereksiz türetilmiş tablo için siparişin garanti edilmemesi GERÇEKTEN mümkün mü?


12

Lukas Eder ile yaptığı bir Twitter görüşmesinde bu soruyu tökezledim .

Doğru davranış en dış sorguya ORDER BY yan tümcesini uygulamak olsa da, burada, DISTINCT, GROUP BY, JOIN veya en dıştaki sorguda başka bir WHERE yan tümcesi kullanmıyoruz, neden bir RDBMS yalnızca gelen sorgu iç sorgu tarafından sıralanmış olarak?

SELECT * 
FROM (
    SELECT * FROM table ORDER BY time DESC
) AS t

Bu örneği PostgreSQL üzerinde çalıştırdığınızda, hem iç sorgu hem de bu türetilmiş tablo örneği ve aynı sonuç kümesi için aynı Yürütme Planını alırsınız.

Bu nedenle, Planlayıcı'nın en dıştaki sorguyu atacağını varsayarım çünkü gereksizdir veya sadece iç tablodaki sonuçlardan geçer.

Herkes bunun böyle olmadığını düşünüyor mu?


4
Türetilmiş bir tablo içinde tarafından bir sıraya izin verilmediğinden, sorgunuzun SQL Server'da başarısız olacağını unutmayın.
a_horse_with_no_name

Neden bu kadar inanılmazsın? Neden bir şey varsayalım? Size bir seçenek bırakan bir program yazdığınızda, kullanıcıların seçiminiz hakkında bir şeyler beklemelerini bekler misiniz? Mantıksal ve fiziksel sorgu optimizasyonu / uygulaması hakkında bilgi edinin.
philipxy

2
"Planlayıcı'nın yalnızca en dıştaki sorguyu atacağını varsayıyorum çünkü gereksiz ya da sadece iç tablodaki sonuçlardan geçiyor." Sen aynı kolaylıkla Planlayıcısı silinmesine neden olacağını varsayabiliriz sipariş maddesini üzerinde anlamsız bağlamında çünkü sorguda.
Wildcard

MariaDB, 2012 hakkında, konuyu tartışıyor. İç eksikliğiORDER BYfarklı kurşun groupwise maks optimizasyonu .
Rick James

1
Aslında, Postgres için haklısın.
Erwin Brandstetter

Yanıtlar:


20

Çoğu veritabanı, ORDER BYbir alt sorgudaki bir ya:

  • İzin verilmiyor: Örneğin, SQL Server, Sybase SQL Anywhere ( TOPveya ile tamamlanmadığı sürece OFFSET .. FETCH)
  • Anlamsız: Örneğin PostgreSQL, DB2 ( OFFSET .. FETCHveya ile tamamlanmadığı sürece LIMIT)

İşte DB2 LUW kılavuzundan bir örnek (benimkini vurgulayın)

Bir alt seçimdeki ORDER BY deyimi, bir sorgu tarafından döndürülen satırların sırasını etkilemez . ORDER BY deyimi, yalnızca en dıştaki tam seçimlerde belirtilirse döndürülen satırların sırasını etkiler.

İfadeler oldukça açık, tıpkı PostgreSQL'ler gibi :

Sıralama seçilmezse, satırlar belirtilmemiş bir sırada döndürülür. Bu durumda gerçek sıra, tarama ve birleştirme planı türlerine ve diskteki sıraya bağlı olacaktır, ancak buna güvenilmemelidir . Belirli bir çıktı sıralaması yalnızca sıralama adımı açıkça seçildiğinde garanti edilebilir.

Bu spesifikasyondan, ORDER BYtüretilmiş bir tablodaki maddeden kaynaklanan herhangi bir siparişin sadece tesadüfi olduğu ve beklenmedik siparişinizle (önemsiz örneğinizdeki çoğu veritabanında yaptığı) tesadüfen eşleşebileceği takip edilebilir, ancak buna güvenmek akıllıca olmaz bu.

DB2 ile ilgili yan not:

Özellikle, DB2 daha az bilinen bir özelliğe sahiptirORDER BY ORDER OF <table-designator> , bu özellik aşağıdaki gibi kullanılabilir:

SELECT C1 FROM
   (SELECT C1 FROM T1
      UNION
    SELECT C1 FROM T2
    ORDER BY C1 ) AS UTABLE
ORDER BY ORDER OF UTABLE

Bu özel durumda, türetilmiş tablonun sıralaması, çoğu dış SEÇİM'de açıkça yeniden kullanılabilir

Oracle ile ilgili yan not:

Yıllardır Oracle'da , yalnızca türetilmiş bir tablo sipariş ettikten sonra makul bir şekilde hesaplanabilen OFFSETsayfalandırma uygulamak bir uygulama olmuştur :ROWNUM

SELECT *
FROM (
  SELECT rownum AS rn, t.* -- ROWNUM here depends on the derived table's ordering
  FROM (
    SELECT * FROM table ORDER BY time DESC
  ) t
) t
WHERE rn BETWEEN 10 AND 20

En azından ROWNUMbir sorguda, gelecekteki Oracle sürümlerinin, henüz çok daha arzu edilebilir ve okunabilir SQL standart OFFSET .. FETCHsözdizimi:

SELECT * FROM table ORDER BY time DESC OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY

Meaningless: E.g. PostgreSQLgerçekten: 'güvenilmez' olmalı, çünkü bu bir şey ifade ediyor. Satırlar iç sorguda sıralanır ve aksi belirtilmedikçe veya yeniden sıralama ek işlemler için fırsat olmadıkça bu sıra dış sorgu düzeylerinde tutulur. Bu sadece bir uygulama detayı olsa bile, anlamsız değildir. Bu, işlevleri birleştirmek için sıralı giriş için kullanılabilir. Kılavuz bile şu kadar ipucu Alternatively, supplying the input values from a sorted subquery will usually work.
veriyor

Postgres için eklediğiniz teklif aslında farklı bir durum için geçerlidir: hayır içeren sorgular ORDER BY.
Erwin Brandstetter

@ErwinBrandstetter: Bu ayrıntılara bir cevap eklemekten çekinmeyin. Şahsen, uygulama detaylarının anlamlı olduğuna katılmıyorum. Sadece bugün, eski günlerde insanların Oracle'a her zaman Oracle 8i'de operasyona göre sıralı bir grup yaptıklarına güvendiğini öğrendim (sanırım), aniden, daha yeni bir sürüm hashed grubunu tanıttı. siparişe güvenilebilir. Başka bir deyişle: Cesur sözlerle ifade etmeyi seviyorum. Anlamsız , oh
Lukas Eder

Zaten bir cevap ekledim. Standart dışı davranışları göz ardı etmeyi seçip seçmemek veya başka iyi tavsiyelerde bulunmak şu sorunun yanındadır: Verilen sorgu için sipariş garantili mi? Postgres içindir. Diğer RDBMS için geçerli değildir (hatta uygulanamaz). Ve bu sadece Postgres'in mevcut tüm sürümleri için geçerlidir , sadece xyz sürümü için değil (belgelendirilmiş) bile belgelenmiştir. Teklifiniz yanıltıcı. Standart dışı davranışı görmezden gelmek istiyorsak, Oracle ile NULL ve boş dizenin aynı olduğuna inanmamızı sağlayabiliriz. Ayrıca soruya dik.
Erwin Brandstetter

@ErwinBrandstetter: İlginç, güncelleme için teşekkürler. Bu, belgelendiğiniz anlamına gelir mi?
Lukas Eder

12

Evet. Bir ORDER BYcümle olmadan çıktı sırası tanımsızdır ve sorgu planlayıcısı bunu bildiğinizi ve anladığınızı varsaymak için kendi amacı dahilindedir.

Dış sorgu bir sipariş belirtmediği için, özellikle sıralamayı destekleyecek bir kümelenmiş dizin veya hiç dizin yoksa bir sıralama işleminden kaçınmak için iç sorgudaki sıralamayı bırakabileceğine karar verebilir. Şimdi değilse , gelecekteki sürümlerde olabilir.

Asla tanımlanmamış davranışlara güvenmeyin. Belirli bir siparişe ihtiyacınız varsa ORDER BY, uygun yerde bir madde verin .


PostgreSQL üzerinde test ederken, ORDER BY tarafından kullanılan sütunda herhangi bir dizin olmadığından sıralama sıralı bir taramadan sonra yapıldı. Hangi RDBMS'nin ORDER BY iç sorgusunu atlayacağını düşünüyorsunuz?
Vlad Mihalcea

5
Ben herhangi biliyorum diyemem olacak onlar her türlü mükemmel isterlerse bunu yapmaya serbesttir sadece, - bu genel standartlar ve ürün özellikleri her ikisine göre mükemmel kabul edilebilir bir optimizasyon olacaktır. SQL Server sorguyu doğrudan reddeder ( TOP 100%geçerli sorgunun taşınabilir olmaması dahil edilmezse, bu projeniz için bir öncelik olmalıdır. Postgres iç sorgudaki sıralamaya uyduğu için şimdi her zaman gelecekte yapacağını ima etmemektedir (veya eski sürümlerde de geçerlidir) bu nedenle her durumda davranışa güvenmekten kaçınmalısınız
David Spillett

1
@VladMihalcea gereksiz "Uzak optimize" yapan bir DBMS ORDER BYolduğunu mariadb: Neden alt sorgusu GELEN bir Sayılan SİPARİŞ BY içinde nedir?
ypercubeᵀᴹ

6

Tanımlanmamış davranışla ilgili en büyük sorun - sizin için çalışıyor, benim için çalışıyor, HDD'yi eşyada yeniden biçimlendiriyor;)

Bir adım geri gidebilir ve bir anlamda haklı olduğunuzu söyleyebiliriz - herhangi bir aklı başında RDBMS'nin iç seçimdeki satırları yeniden düzenlemesinin dünyevi bir nedeni yoktur. Ancak garanti edilmez - yani gelecekte bir sebep olabilir ve satıcılar bunu yapmakta özgürdür. Bu davranışa dayanan herhangi bir kodun, bir satıcının bir API POV'den kopan bir değişiklik olmadığı için, yayınlama yükümlülüğü altında olmayacağı bir değişikliğin merhametinde olduğu anlamına gelir.


2
Siparişi dışarıdan optimize etmesinin bir nedeni hızdır. Satırları farklı bir sırayla döndürmek daha verimli olabilir.
TomTom

2
Özellikle, sunucu tabloyu okumak için paralellikten yararlanabilir. Bunu yaparsa ve bir siparişin uygulanmasına gerek yoksa, satırları geri alırsınız, ancak iş parçacıkları bunları okur. (SQL Server aslında bunu yapar, böylece SELECThiçbir ORDER BYgerçekten olmayan, sadece teoride değil veya veriler değiştiği için belirsizdir.)
Jeroen Mostert

@JeroenMostert: Tanımsız davranış sadece daha da kötüleşiyor. Düzensizse ve delta diziye dizine eklenirse ne olur?
Joshua

2

Bu gereksiz türetilmiş tablo için siparişin garanti edilmemesi GERÇEKTEN mümkün mü?

Şu anda var olan tüm Postgres (test ettiğiniz) sürümlerinin yanıtı : Hayır - bu sorgu için. Sıralama düzeni garanti edilir.

Microsoft, ORDER BYalt sorgulara bile izin vermediğinden SQL sunucusu çalışanları bundan rahatsız olacaktır . Yine de Postgres'deki bu basit sorgu için sıralama düzeni garanti edilir. ORDER BYalt sorguda uygulanır ve dış sorgu sırasını değiştirebilecek bir şey yapmaz.

Kılavuz, Toplama İşlevleri bölümündeki ipucunu bile işaret ediyor :

Alternatif olarak, sıralı bir alt sorgudan giriş değerlerinin sağlanması genellikle işe yarayacaktır.

Bunun yalnızca dış sorgu düzeyleri sırayı değiştirebilecek işlemler eklemediğinde geçerli olduğunu unutmayın. Bu nedenle, basit durum için yalnızca "garanti edilir" ve bu SQL standardı tarafından desteklenmez. Postgres, ek işlemler için uygunsa yeniden sipariş vermekte serbesttir. Şüphe durumunda ORDER BYdış tarafa bir tane daha ekleyin SELECT. (Bu durumda, ORDER BYbu basit sorgu için iç kısım gereksiz gürültü olacaktır.)


O zaman doğru "table"basit, temel tablo ama karmaşık bir görünüm veya bir bölümlenmiş tablo değil mi? Planın paralel yürütülmesi de doğru mu? Postgres 10'da da bu doğru mu? (Sadece soruyorum, bu soruların herhangi birinin cevabından emin değilim.)
ypercubeᵀᴹ

@ ypercubeᵀᴹ: Bunların hepsi için Postgres 10'u test etmedim, ancak her durumda doğru olduğundan eminim. Sipariş uygulanır ve basit durum için dış sorguda değiştirilmez.
Erwin Brandstetter
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.