MySQL'deki ORDER BY FIELD () nasıl dahili olarak çalışır?


37

Cümlenin nasıl ORDER BYçalıştığını ve FIELD()fonksiyonun nasıl çalıştığını anlıyorum . Anlamak istediğim, ikisinin de sıralamak için nasıl birlikte çalıştığı. Satırlar nasıl alınır ve sıralama düzeni nasıl türetilir?

+----+---------+
| id |  name   |
+----+---------+
|  1 | stan    |
|  2 | kyle    |
|  3 | kenny   |
|  4 | cartman |
+----+---------+ 

SELECT * FROM mytable WHERE id IN (3,2,1,4) ORDER BY FIELD(id,3,2,1,4)

Yukarıdaki sorgu sonuçlanacaktır

+----+---------+
| id |  name   |
+----+---------+
|  3 | kenny   |
|  2 | kyle    |
|  1 | stan    |
|  4 | cartman |
+----+---------+ 

SİPARİŞ BY 3, 2, 1, 4 demeye benzer bir şey

SORULARI

  • Bu dahili olarak nasıl çalışır?
  • MySQL nasıl satır alır ve sıralama düzenini nasıl hesaplar?
  • MySQL'in id sütununa göre sıralaması gerektiğini nereden biliyor?

1
Sorgunuzun bu varyasyonunu deneyin: SELECT *, FIELD(id,3,2,1,4) AS f FROM mytable WHERE id IN (3,2,1,4);Ardından ekleyin ORDER BY fveya ORDER BY FIELD(id,3,2,1,4)tekrar deneyin.
ypercubeᵀᴹ

Yanıtlar:


64

Kayıt için

SELECT * FROM mytable WHERE id IN (1,2,3,4) ORDER BY FIELD(id,3,2,1,4);

iyi çalışmalı çünkü listedeki WHEREmaddeyi sipariş etmek zorunda değilsin

Nasıl çalıştığına gelince,

Her çeşit fantezi siparişi oluşturabilirsiniz

Örneğin, IF () işlevini kullanarak

SELECT * FROM mytable
WHERE id IN (1,2,3,4)
ORDER BY IF(FIELD(id,3,2,1,4)=0,1,0),FIELD(id,3,2,1,4);

Bu, listenin başında ilk 4 kimliğin görünmesine neden olur, Aksi takdirde, alt tarafta belirir. Neden?

İçinde ORDER BY0 veya 1 olsun.

  • İlk sütun 0 ise, ilk 4 kimliğin herhangi birinin görünmesini sağlayın.
  • İlk sütun 1 ise, daha sonra görünmesini sağlayın

İlk sütunda DESC ile çevirelim

SELECT * FROM mytable
WHERE id IN (1,2,3,4)
ORDER BY IF(FIELD(id,3,2,1,4)=0,1,0) DESC,FIELD(id,3,2,1,4);

İçinde, ORDER BYhala 0 veya 1 olsun.

  • İlk sütun 1 ise, ilk 4 kimliden başka bir şey yapmayın.
  • İlk sütun 0 ise, ilk 4 kimliği orijinal sırada görünmesini sağlayın.

GERÇEK SORULARINIZ

Bu konuda ciddiyetle içsel istiyorsanız , Kitabın 189 ve 192. Sayfalarına bakınız.

MySQL Internals

Gerçek bir derin dalış için.

Temelde, ORDER *order( ORDER BYİfade ağacı) adında bir C ++ sınıfı vardır . Olarak JOIN::prepare, *orderbilinen bir fonksiyonun kullanılır setup_order(). Neden JOINsınıfın ortasında ? Her sorgu, tek bir masaya karşı bile bir sorgu, her zaman bir JOIN olarak işlenir (Yazımı görün. Bir JOIN koşulu ile bir WHERE koşulu arasında bir yürütme farkı var mı? )

Bütün bunların kaynak kodu sql/sql_select.cc

Açıkça, ORDER BYağaç değerlendirmesini yapacak FIELD(id,3,2,1,4). Dolayısıyla, 0,1,2,3,4 sayıları, ilgili satıra referans yapılırken sıralanan değerlerdir.


1
Bu olağanüstü mükemmel bir açıklamadır. Bu yöntemleri kullanarak, kümenin maksimumu olan bir birincil ilk değer olan 3 emir, sonra FIELD ve sonra FIELD kümesinde olmayanlar için başka bir sütun elde edebildim. Bir süre önce hayal edemediğim bir şey. Bunun gerçekten nasıl çalıştığını açıklamaya zaman ayırdığınız için teşekkür ederiz.
Lizardx

NHer ikisinde de INve içinde değerler olduğunu varsayalım FIELD. Bu örnekte N=4. Bu sorgunun en azından ~N^2işlem yapacağı doğru mu anlıyorum . Çünkü her FIELDhesaplama, ~Nher satır için bir kez karşılaştırma yapar . Eğer öyleyse, bu büyük için oldukça yavaştır NBelki de çok iyi bir yaklaşım değil mi?
Gherman

@Gherman FIELD()İşlev bir O(1)işlem olmalıdır FIELD(), çünkü sayısal bir dizini vardır id. Bu yüzden başka bir şey göremiyorum ama O(n)satırlara dayanıyor. Yapmanız gereken FIELD()herhangi bir yinelemeli işlem GREATEST()görmüyorum.
RolandoMySQLDBA

@RolandoMySQLDBA Demek istediğim, eğer karşılaştırılacak argümanlar varsa FIELD, No zaman Nkarşılaştırmalar yapacak . Yapmazsak, bir sayıyı Ndiğer sayılarla karşılaştırmak başka nasıl olacak O(N)? Düşünebildiğim tek olasılık, bir karma veya bir argüman ağacı gibi özel bir veri yapısıyla bir çeşit optimizasyon. Aslında INbunun böyle bir optimizasyona sahip olduğunu biliyorum . Bilmiyorum FIELD. "Sayısal dizin" ile ne demek istiyorsunuz?
Gherman

1
Hey @RaymondNijland, CASE ifadesi daha anlaşılır bir durumdur. Bu durumda, sözdizimsel şekerin daha az yazması vardır.
RolandoMySQLDBA

1

Belki bu, gerçek koddan çok uzakta olacaktır, bu yüzden istediğinizden yeterince düşük seviyede değil:

MySQL verileri sıralı olarak almak için dizini kullanamadığında, seçili tüm sütunlarla ve bazı ek verilerle geçici bir tablo / sonuç kümesi oluşturur - bunlardan biri, her satır için ORDER BY ifadesi değerinin sonuçlarını depolamak için bir tür sütundur - daha sonra bu tmp tablosunu, hangi sütuna göre sıralayacağınızı gösteren bir "filesort" rutine gönderir. Bundan sonra sıralar sıralanır, böylece onları birer birer seçebilir ve seçilen sütunları geri getirebilir.


Bu açıklama, FIELDbilgisayardaki fonksiyonun nasıl olduğunu hesaba katmaz . Performans üzerinde önemli bir etkisi olabileceğinden korkuyorum.
Gherman

@Gherman sanmıyorum, çok uzun bir argüman listesi kullanmıyorsanız (işlev argüman sayısına doğrusal olduğu için . Veri erişimi, basit karşılaştırmalardan daha yavaş bir büyüklük
sırasıdır

Evet, uzun argüman listesi. Bu örnekte kayıtların olduğu kadar çok argüman var.
Gherman

Sadece yüzlerce veya binlerce kişiyi etiketlerdim ve sonra yine de başka sorunlarla karşılaşırsınız (sorgu boyutu vb.)
jkavalik

neden yüzlerce sonuç değil? Çok mu
Gherman
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.