Bireysel sorgular katılımdan daha mı hızlı?


44

Kavramsal soru: Bireysel sorgular katılımdan daha hızlı mıdır, yoksa: Müşteri tarafında istediğim her bilgiyi bir SELECT ifadesine sıkıştırmaya mı çalışmalıyım yoksa uygun göründüğü kadarını kullanmalı mıyım?

TL; DR : Eğer benim katıldı sorgu bireysel sorgular çalışan daha uzun sürer, bu benim hatam ya bu beklenen nedir?

Birincisi, çok veritabanı bilgili değilim, bu yüzden sadece ben olabilirim, ancak birden fazla tablodan bilgi almak zorunda kaldığımda, bu bilgiyi ayrı ayrı masalarda birden fazla sorgu kullanarak elde etmenin "genellikle" daha hızlı olduğunu fark ettim (belki de basit bir iç birleşim içeren) ve tüm verileri tek bir sorguda elde edebileceğim (karmaşık) birleştirilmiş bir sorgu yazmayı denemek için verileri istemci tarafında birleştirin.

Birlikte son derece basit bir örnek vermeye çalıştım:

SQL Fiddle

Şema Kurulumu :

CREATE TABLE MASTER 
( ID INT NOT NULL
, NAME VARCHAR2(42 CHAR) NOT NULL
, CONSTRAINT PK_MASTER PRIMARY KEY (ID)
);

CREATE TABLE DATA
( ID INT NOT NULL
, MASTER_ID INT NOT NULL
, VALUE NUMBER
, CONSTRAINT PK_DATA PRIMARY KEY (ID)
, CONSTRAINT FK_DATA_MASTER FOREIGN KEY (MASTER_ID) REFERENCES MASTER (ID)
);

INSERT INTO MASTER values (1, 'One');
INSERT INTO MASTER values (2, 'Two');
INSERT INTO MASTER values (3, 'Three');

CREATE SEQUENCE SEQ_DATA_ID;

INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 1, 1.3);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 1, 1.5);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 1, 1.7);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 2, 2.3);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 3, 3.14);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 3, 3.7);

Sorgu A :

select NAME from MASTER
where ID = 1

Sonuçlar :

| NAME |
--------
|  One |

Sorgu B :

select ID, VALUE from DATA
where MASTER_ID = 1

Sonuçlar :

| ID | VALUE |
--------------
|  1 |   1.3 |
|  2 |   1.5 |
|  3 |   1.7 |

Sorgu C :

select M.NAME, D.ID, D.VALUE 
from MASTER M INNER JOIN DATA D ON M.ID=D.MASTER_ID
where M.ID = 1

Sonuçlar :

| NAME | ID | VALUE |
---------------------
|  One |  1 |   1.3 |
|  One |  2 |   1.5 |
|  One |  3 |   1.7 |

Tabii ki, bunlarla hiçbir performansı ölçmedim, ancak biri gözlemleyebilir:

  • A + B sorgusu, Query C ile aynı miktarda kullanılabilir bilgi verir.
  • A + B müşteriye 1 + 2x3 == 7 "Veri Hücreleri" döndürmelidir
  • C'nin müşteriye 3x3 == 9 "Veri Hücreleri" döndürmesi gerekiyor, çünkü birleştirme ile doğal olarak sonuç kümesine fazlalık eklerim.

Bundan genelleme (olduğu kadarıyla getirildi):

Birleştirilmiş bir sorgu her zaman aynı miktarda bilgi alan ayrı ayrı sorgulardan daha fazla veri döndürmelidir. Veritabanının verileri bir araya getirmesi gerektiğinden, büyük veri kümeleri için, tek bir birleştirilen sorguda veri tabanının bireysel olanlardan daha fazla çalışması gerektiği varsayılabilir, çünkü (en azından) müşteriye daha fazla veri döndürmesi gerekir.

Bundan bir müşteri tarafı sorgusunu çoklu sorgulara bölmenin daha iyi performans sağladığını gözlemlediğimde, bunun sadece gitmenin yolu olduğunu mu yoksa bunun yerine birleştirilmiş sorguyu batırdığım anlamına mı gelir?


Yorumlar uzun tartışmalar için değildir; bu konuşma sohbete taşındı .
Jack Douglas

1
Ben bir kriter koştum ve sonuçları Medium ile ilgili bir makalede yayınladım . Buraya bir cevap eklerdim, ama zaten başka bir soruda yaptım ve aynı cevabı birden fazla soruya göndermek kaşlarını çattı .
Benjamin

Yanıtlar:


45

Bireysel sorgular katılımdan daha mı hızlı mı yoksa: Müşteri tarafında istediğim her bilgiyi bir SELECT ifadesine sıkıştırmaya mı çalışmalıyım yoksa uygun göründüğü kadar mı kullanmalıyım?

Herhangi bir performans senaryoda, gerek test ve ölçüm hızlı olduğunu görmek için çözümler .

Bununla birlikte, hemen hemen her zaman, düzgün bir şekilde ayarlanmış bir veritabanından ayarlanmış bir birleştirilmiş sonucun, kaynak satırları müşteriye geri göndermekten ve daha sonra oraya katılmaktan daha hızlı ve daha ölçeklenmiş olacağı söylenir. Özellikle, girdi kümeleri büyükse ve sonuç kümesi küçükse - aşağıdaki sorguyu her iki strateji bağlamında düşünün: her biri 5 GB olan iki tabloyu, 100 satırlık bir sonuç kümesiyle birleştirin. Bu aşırı bir şey ama sen benim görüşümü anladın.

Birden fazla tablodan bilgi almam gerektiğinde, bu bilgiyi ayrı ayrı masalarda (belki de basit bir iç birleşim içeren) birden fazla sorgulama yoluyla elde etmenin ve denemek için verileri bir araya getirmenin "genellikle" daha hızlı olduğunu fark ettim. Tüm verileri bir sorguda bulabildiğim (karmaşık) bir birleşik sorgu yazmak için.

Veri tabanı şeması veya dizinlerinin, attığınız sorgulara daha iyi hizmet verebilmek için geliştirilmesi olasıdır.

Birleştirilmiş bir sorgu her zaman aynı miktarda bilgi alan ayrı ayrı sorgulardan daha fazla veri döndürmelidir.

Genelde durum böyle değil. Girdi kümeleri büyük olsa bile çoğu zaman sonuç kümesi girdilerin toplamından çok daha küçük olacaktır.

Uygulamaya bağlı olarak, istemciye döndürülen çok büyük sorgu sonuç kümeleri hemen bir kırmızı bayraktır: müşteri veritabanına daha yakın yapılamayacak kadar büyük bir veri kümesiyle ne yapıyor? Bir kullanıcıya 1.000.000 satır göstermenin en az söz etmesi şüphelidir. Ağ bant genişliği de sınırlı bir kaynaktır.

Veritabanının verileri bir araya getirmesi gerektiğinden, büyük veri kümeleri için, tek bir birleştirilen sorguda veri tabanının bireysel olanlardan daha fazla çalışması gerektiği varsayılabilir, çünkü (en azından) müşteriye daha fazla veri döndürmesi gerekir.

Şart değil. Veriler doğru endekslenirse, birleştirme işleminin büyük miktarda veri taramasına gerek kalmadan veritabanında daha verimli yapılması daha olasıdır. Dahası, ilişkisel veritabanı motorları katılmak için özellikle düşük bir seviyede optimize edilmiştir ; müşteri yığınları değil.

Bundan bir müşteri tarafı sorgusunu çoklu sorgulara bölmenin daha iyi performans sağladığını gözlemlediğimde, bunun sadece gitmenin yolu olduğunu mu yoksa bunun yerine birleştirilmiş sorguyu batırdığım anlamına mı gelir?

Veritabanlarına gelince deneyimsiz olduğunuzu söylediğinizden beri, veritabanı tasarımı ve performans ayarlama hakkında daha fazla bilgi edinmenizi öneririm. Sorunun burada yattığına eminim. Verimsiz yazılmış SQL sorguları da mümkündür, ancak sorun olma ihtimali daha az olan basit bir şema ile.

Şimdi, bu performansı arttırmanın başka yolları olmadığını söylemek değildir. Amaç bir tür önbelleğe alma mekanizması kullanmaksa, orta ila büyük veri kümesini taramayı ve istemciye iade etmeyi seçebileceğiniz senaryolar vardır. Önbellekleme harika olabilir, ancak tasarımınıza karmaşıklık getirir. Önbelleğe alma, uygulamanız için uygun olmayabilir.

Herhangi bir yerde bahsedilmeyen bir şey, veritabanından döndürülen verilerde tutarlılığı korumaktır. Ayrı sorgular kullanılıyorsa, her sorgu kümesi için bir anlık görüntü yalıtımı biçimi kullanılmadığı sürece (birçok faktör nedeniyle) tutarsız verilerin döndürülmesi daha olasıdır.


Ağ bant genişliği için +1 de sonlu bir kaynaktır.
Hari Harker

OP, KATILAN veri sonuç kümelerinin her zaman daha büyük olduğunu söylüyor. > Birleştirilmiş bir sorgu her zaman bireysel sorgulardan daha fazla veri döndürmelidir. Bunun nesnel olarak doğru olduğunu düşünüyorum (> = için), örneğin sonuç kümeleri boyut olarak farklılık gösterir, bu nedenle tel üzerinden daha fazla veri elde edilir. Bunun doğru olmadığı bir örnek var mı? Yazarlara katılırsam -> Yazılar ve Yazarlar, 1MB JSON alanı olan "biyografi" adlı bir alana sahiptir, 100 Yazılı Yazar için, tel üzerinden 100 MB'a 1 MB iletirim. Bu yanlış mı?
hytromo

6

Tabii ki, bunlarla hiçbir performans ölçmedim

Bazı iyi örnek kodları bir araya getirdin. SQL Fiddle'daki zamanlamaya baktın mı? Bazı kısa bilimsel olmayan performans testleri bile gösterinizdeki 3. sorgunun, bir veya iki sorguyu ayrı ayrı çalıştırmak için aynı miktarda zaman alacağını gösterecektir. Kombine bir ve iki, üçe iki kat daha uzun sürer ve bu, herhangi bir müşteri tarafının birleştirilmesinden önce gerçekleşir.

Verileri artırdıkça, bir ve iki numaralı sorgunun hızı artacaktır, ancak veritabanı birleştirme işlemi hala daha hızlı olacaktır.

Ayrıca, iç birleştirme verileri elimine ederse ne olacağını düşünmelisiniz.


2

Sorgu iyileştirici de dikkate alınmalıdır. Rolü, bildirimsel SQL'inizi almak ve prosedür adımlarına dönüştürmektir. Prosedürel adımların en etkin kombinasyonunu bulmak için, indeks kullanımı, çeşitler, ara sonuç kümelerini önbelleğe alma ve diğer her türlü şeyleri de inceleyecektir. Oldukça basit sorgular gibi görünse bile, permütasyon sayısı oldukça fazla olabilir.

En iyi planı bulmak için yapılan hesaplamanın çoğu, tabloların içindeki verilerin dağılımından kaynaklanmaktadır. Bu dağılımlar örneklenir ve istatistik nesneleri olarak saklanır. Bunlar yanlışsa, iyimserliği zayıf seçimler yapmaya yönlendirir. Planın başındaki zayıf seçimler, daha sonra kartopu etkisiyle daha kötü seçimlere bile yol açar.

Orta büyüklükteki bir sorgunun, dakikalarca sürmesi gereken mütevazı miktarda veriyi döndürmesi bilinmiyor. Doğru indeksleme ve iyi istatistikler daha sonra bunu milisaniyeye indirir.


-3

Birden çok sorgu gitmek için yoludur. Bunun gibi basit senaryoları ele alırsanız - sorgu iyileştiricinin maliyet ek yükü bir faktördür. Daha fazla veriyle, birleştirme işleminin ağ yetersizliği (yedekli satırlar) gelir. Yalnızca çok daha fazla veride verimlilik vardır.

Sonunda, deneyimlediğiniz şey birçok geliştiricinin gördüğü şeydir. DBA'lar her zaman “hayır, katıl” diyorlar, ancak gerçek şu ki: bu durumda birden fazla basit seçim yapmak daha hızlı.


5
Bir birleşimde "ağ verimsizliği" yok - hepsi veritabanı sunucusunda oluyor, bu yüzden herhangi bir ağ yok (bir db bağlantısı üzerinden katılmadığınız sürece!)
Chris Saxon

2
Ağ katmanının sıkıştırılmış olup olmadığını düşünebilirsiniz. Oracle'ın SQL * Net'i, aynı sütunda tekrarlayan değerlerin verimli bir şekilde sıkıştırıldığını gösterir.
David Aldridge

3
@ TomTom'un bir noktası olabilir ya da olmayabilir (David Aldridge'in işaret ettiği gibi, sıkıştırma önemlidir) ancak ifadeleriniz kafa karıştırıcıdır. "Birleşimin ağ yetersizliği" ? Gerçekten, bunu düzelttiğin için ne demek istediğin belli.
ypercubeᵀᴹ

@ChrisSaxon olduğundan emin olun, resim "title-> base-> table-rows" raporunuz için tablolara sahip ve tüm satırlara ihtiyacınız var, böylece bu 3 tabloyu içselleştirebilirsiniz. Her tablonun uzun varcharları vardır, bu yüzden bu satır varyantlarını tekrarladığınız her satır için olan şey budur. Uygulama katmanı tüm bu dizgiler için bellek ayırmalı ve sonra bunları modelinize göre gruplandırmalıdır. Yani demek istediği bu, daha fazla veri gönderildi
MIKE

@MIKE, birleştirmeye değil, seçtiğiniz ifadelere bağlıdır. Ve ağ sıkıştırma olabilir. Oracle Database SQL * Net, yinelenen çift değerleri kaldırır nicetheory.io/2018/01/11/…
Chris Saxon
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.