A = 0 ve b = 0 ve… z = 0 a + b + c + d = 0'a karşı


20

Bu, cevabını bulamadığım basit bir soru.

Bir varsa performans açısından, WHEREörneğin maddesini a=0 and b=0 and ... z=0ben o koşulu yerini ise, Keşke benim herhangi performansı elde a+b+...+z=0?

Başka bir deyişle, aşağıdakileri değiştirerek herhangi bir performans kazancı var mı?

Select * 
From MyTable 
Where A=0 and B=0 and C=0 and D=0...

İle

Select * 
From MyTable 
Where A+B+C+D=0...

Endekslere bağlı olabileceğini biliyorum, ama bu amaçla sadece hiçbir indeks olmadığını söyleyelim. Aritmetik işleç (+) "OR" veya "AND" Mantıksal İşleci'nden daha iyi performans gösteriyor mu?

Eklemenin VE'ler veya OR'ler ile birden fazla koşuldan daha iyi performans sergilediği izlenimindeyim.

Test sonuçları

4.2 milyon satırlık bir tabloda

Geri dönen satırlar A = 0 B = 0 ve C = 0 -> 351748 Satırlar

Ekleme (A + B + C = 0) 5 saniye sürerken, Mantıksal koşullar A = 0 ve B = 0 ve C = 0 11 saniye sürdü.

Diğer yandan

Geri dönen satırlar A <> 0 B <> 0 veya C <> 0 -> 3829750 Satır 58 saniye

Dönen satırlar F65 + F67 + f64 <> 0 -> 3829750 Satırlar 57 saniye

OR için önemli bir fark yok gibi görünüyor.

Gbn ile katılıyorum:

A -1 ve B 1 ise, A + B = 0 ama A = 0 ve B = 0 yanlış

ve AMtwo ile:

ABS (A) + ABS (B) + ABS (C) + ABS (D) ... Yalnızca pozitif değerler bekleseniz bile, sütun negatif değerleri kabul ederse, bir değerle karşılaşabileceğinizi varsaymalısınız.

Düşündüğüm gibi sonuçlar çok etkileyici, toplama mantıksal operatörlerden çok daha hızlı görünüyor.

A = Float, B = Para ve C = Float. Kullanılan sorgu gösterildiği gibidir. Benim durumumda, hepsi pozitif sayılar. Dizin yok. Eklemenin Mantıksal koşullardan daha hızlı olacağı aklımda sadece mantıklı!


Bunlar boolean mı? 4 (örneklerde) veya 26 (başlıkta) hakkında kaç sütundan bahsediyorsunuz? Bir fark yaratır. SQL Server'ın hangi sürümü? FLOAT ve MONEY nerede oynuyor? Kaç satır varsayıyoruz? Bu sorunun tonlarca faktörü var.
Evan Carroll

@Evan Carroll Boolean değiller, endekslenmemiş sayılar (int, float, para, vb.) SQL Sürümü ne olursa olsun (SQL2012 ve üstü), satır veya sütun sayısı, Soru, hangi operatörün daha iyi performans gösterdiğini - aritmetik işleçleri bulmaktı. Gördüğünüz gibi Max Vernon teoriyi örnekleriyle mükemmel bir şekilde gösteriyor.
JohnG

Yanıtlar:


46

Sorunuzda, ekleme seçeneğinin ayrı sütunları karşılaştırmaktan daha hızlı olduğunu "kanıtladığınız" yerde hazırladığınız bazı testleri ayrıntılı olarak açıklıyorsunuz. Test metodolojinizin @gbn ve @srutzky'nin belirttiği gibi çeşitli şekillerde kusurlu olabileceğinden şüpheleniyorum.

İlk olarak, SQL Server Management Studio'yu (veya kullandığınız herhangi bir istemciyi) test etmediğinizden emin olmanız gerekir. Örneğin, SELECT *3 milyon satırlı bir tablodan çalıştırıyorsanız , SSMS'nin satırları SQL Server'dan çekme ve bunları ekranda oluşturma yeteneğini test edersiniz. SELECT COUNT(1)Ağ boyunca milyonlarca satırı çekme ve bunları ekranda oluşturma ihtiyacını ortadan kaldıran bir şey kullanmaktan çok daha iyisiniz .

İkincisi, SQL Server'ın veri önbelleğinin farkında olmanız gerekir. Genellikle, verileri depolamadan okuma ve bu verileri işleme, bir soğuk önbellekten test ediyoruz (yani SQL Server'ın arabellekleri boş). Bazen, tüm testlerinizi sıcak bir önbellek ile yapmak mantıklıdır, ancak testinize açıkça aklınızda yaklaşmanız gerekir.

Soğuk önbellek testi için, testin her çalıştırılmasından önce CHECKPOINTve çalıştırmanız gerekir DBCC DROPCLEANBUFFERS.

Sorunuzda sorduğunuz test için aşağıdaki test yatağını oluşturdum:

IF COALESCE(OBJECT_ID('tempdb..#SomeTest'), 0) <> 0
BEGIN
    DROP TABLE #SomeTest;
END
CREATE TABLE #SomeTest
(
    TestID INT NOT NULL
        PRIMARY KEY 
        IDENTITY(1,1)
    , A INT NOT NULL
    , B FLOAT NOT NULL
    , C MONEY NOT NULL
    , D BIGINT NOT NULL
);

INSERT INTO #SomeTest (A, B, C, D)
SELECT o1.object_id, o2.object_id, o3.object_id, o4.object_id
FROM sys.objects o1
    , sys.objects o2
    , sys.objects o3
    , sys.objects o4;

SELECT COUNT(1) 
FROM #SomeTest;

Bu, makinemde 260.144.641 sayısını döndürüyor.

"Ekleme" yöntemini test etmek için çalıştırın:

CHECKPOINT 5;
DBCC FREEPROCCACHE;
DBCC DROPCLEANBUFFERS;

SET STATISTICS IO, TIME ON;
GO
SELECT COUNT(1)
FROM #SomeTest st
WHERE (st.A + st.B + st.C + st.D) = 0;
GO
SET STATISTICS IO, TIME OFF;

Mesajlar sekmesi şunları gösterir:

'#SomeTest' tablosu. Tarama sayısı 3, mantıksal okuma 1322661, fiziksel okuma 0, okuma öncesi okuma 1313877, lob mantıksal okuma 0, lob fiziksel okuma 0, lob okuma önceden okuma 0.

SQL Server Yürütme Süreleri: CPU süresi = 49047 ms, geçen süre = 173451 ms.

"Ayrık sütunlar" testi için:

CHECKPOINT 5;
DBCC FREEPROCCACHE;
DBCC DROPCLEANBUFFERS;

SET STATISTICS IO, TIME ON;
GO
SELECT COUNT(1)
FROM #SomeTest st
WHERE st.A = 0
    AND st.B = 0
    AND st.C = 0
    AND st.D = 0;
GO

SET STATISTICS IO, TIME OFF;

yine mesajlar sekmesinden:

'#SomeTest' tablosu. Tarama sayısı 3, mantıksal okumalar 1322661, fiziksel okumalar 0, okuma öncesi okumalar 1322661, lob mantıksal okumalar 0, lob fiziksel okumalar 0, lob okuma öncesi okumalar 0.

SQL Server Yürütme Süreleri: CPU süresi = 8938 ms, geçen süre = 162581 ms.

Yukarıdaki istatistiklerden, 0'a kıyasla ayrık sütunlarla ikinci varyantı görebilirsiniz, geçen süre yaklaşık 10 saniye daha kısadır ve CPU süresi yaklaşık 6 kat daha azdır. Yukarıdaki testlerimdeki uzun süreler çoğunlukla diskten çok sayıda satır okumanın bir sonucudur. Satır sayısını 3 milyona düşürürseniz, oranların yaklaşık olarak aynı kaldığını görürsünüz, ancak disk G / Ç'nin çok daha az etkisi olduğu için geçen süreler belirgin bir şekilde düşer.

"Toplama" yöntemi ile:

'#SomeTest' tablosu. Tarama sayısı 3, mantıksal okumalar 15255, fiziksel okumalar 0, okuma öncesi okumalar 0, lob mantıksal okumalar 0, lob fiziksel okumalar 0, lob okuma öncesi okumalar 0.

SQL Server Yürütme Süreleri: CPU süresi = 499 ms, geçen süre = 256 ms.

"Ayrık sütunlar" yöntemiyle:

'#SomeTest' tablosu. Tarama sayısı 3, mantıksal okumalar 15255, fiziksel okumalar 0, okuma öncesi okumalar 0, lob mantıksal okumalar 0, lob fiziksel okumalar 0, lob okuma öncesi okumalar 0.

SQL Server Yürütme Süreleri: CPU süresi = 94 ms, geçen süre = 53 ms.

Bu test için gerçekten çok büyük bir fark ne olacak? Uygun bir dizin, örneğin:

CREATE INDEX IX_SomeTest ON #SomeTest(A, B, C, D);

"Ekleme" yöntemi:

'#SomeTest' tablosu. Tarama sayısı 3, mantıksal okuma 14235, fiziksel okuma 0, okuma öncesi okuma 0, lob mantıksal okuma 0, lob fiziksel okuma 0, lob okuma önceden okuma 0.

SQL Server Yürütme Süreleri: CPU süresi = 546 ms, geçen süre = 314 ms.

"Ayrık sütunlar" yöntemi:

'#SomeTest' tablosu. Tarama sayısı 1, mantıksal okumalar 3, fiziksel okumalar 0, okuma öncesi okumalar 0, lob mantıksal okumalar 0, lob fiziksel okumalar 0, lob okuma öncesi okumalar 0.

SQL Server Yürütme Süreleri: CPU süresi = 0 ms, geçen süre = 0 ms.

Her bir sorgu için yürütme planı (yukarıdaki dizin yerinde) oldukça açıklayıcıdır.

Tüm indeksin taranması gereken "ekleme" yöntemi:

resim açıklamasını buraya girin

ve baştaki dizin sütununun Asıfır olduğu dizinin ilk satırını arayabilen "ayrık sütunlar" yöntemi :

resim açıklamasını buraya girin


24

Diyelim ki A, B, C ve D'de bir indeksiniz var. Filtrelenebilir.

Bu, ekleme işleminden sonra indeksi kullanma olasılığı daha yüksektir.

Where A=0 and B=0 and C=0 and D=0

Diğer yandan, A -1 ve B 1 ise A+B=0, doğrudur ancak A=0 and B=0yanlıştır.


7

(Lütfen bu cevabın Soruda belirtilen herhangi bir testten önce gönderildiğini unutmayın: Soru metni Test sonuçları bölümünün hemen üstünde sona erdi .)

Ayrı bir ANDkoşulun tercih edileceğini tahmin ediyorum, çünkü optimizasyon cihazının tek bir tanesi 0'a eşit değilse , önce bir hesaplama yapmaya gerek kalmadan operasyonu kısa devre yapma olasılığı daha yüksek olacaktır .

Bu performansın bir sorudur çünkü Yine, ilk on cevabı belirlemek için bir test kurmalıyım sizin donanım. Test kodunuzu göstererek bu sonuçları bildirin ve iyi bir test olduğundan emin olmak için başkalarından incelemelerini isteyin. Düşünmediğiniz başka faktörler de olabilir.


3

Bazı genel akıl yürütmeler, eğer elinizde herhangi bir dizin yoksa, seçtiğiniz iki çözümden hangisinin çok önemli olacağını düşünmüyorum, ikisi de kötü performans gösterecektir. Öte yandan yüklemdeki sütunlardan bir veya daha fazlasında bir dizin varsa, ikincisi muhtemelen ikincisinden daha iyi performans gösterecektir, çünkü ikincisi muhtemelen dizin (ler) i kullanamayacaktır.

Disjunction (OR) genel olarak bağlaçlardan (AND) daha kötü performans gösterir, ancak disjunction ile ilgili bir sorunuz olsa bile paramı birincisine koyacağım.


2

Bu basit bir soru

Hayır öyle değil. Bu (bir tür) soru, birçok DBA ve yazılım geliştiricisine her gün neyin rahatsız olduğunu ve önemsiz olduğunu gösteriyor.

cevabını bulamıyorum.

Evet, yapmayacaksınız. En azından genel bir cevap değil. Her şeyden önce, büyük ölçüde hangi RDBMS'yi kullandığınıza bağlı olacaktır (Tamam, kullanıyorsunuz , ancak yine de). RDBMS'nizin bir sürümünden diğerine geçtiğinizde bile değişebilir.

Daha sonra, plan optimize edici vb için sorunu karıştıran alt seçimler / birleşimler varsa, örneğin DB'nizin verileri nasıl sakladığı gibi diğer küçük ayrıntılara bağlı olabilir. Optimize edici, kaç satıra sahip olduğunuzu ...

Gerçek dünya testi yapmak genellikle böyle soruları çözmenin tek yararlı yoludur. Ayrıca, böyle "arcane" optimizasyonları ile kazanılan kazançlar genellikle endekslerin akıllıca seçilmesiyle on kat daha fazla yutulur, bu yüzden endekslerin kullanımı gerçekten göz ardı edilmeden önce üzerinde çok fazla zaman harcamadan rahatsız olmazdım.


0

Bu bariz olabilir, ama sütun ise INT, o zaman a+b+czaman sıfır bile eşit olabilir hiçbiri bunlardan aslında sıfırdır. İki farklı şeyi test ediyorsunuz!


Az önce @gbn yanıtında bundan bahsettiğini fark etti.
Ross Presser
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.