Favori performans ayarlama püf noktaları [kapalı]


126

Performans ayarı gerektiren bir sorgunuz veya saklı yordamınız olduğunda, denediğiniz ilk şeylerden bazıları nelerdir?


İşte bazı SQL Server Sorgu Optimizasyon püf noktaları
SQLMenace

Bunun yapıcı olmadığını ve Google'da aranabileceğini kabul ediyorum, ancak neden 118 uv var ?! :)
FLICKER

Yanıtlar:


114

İşte bana optimizasyon hakkında soran birine her zaman verdiğim kullanışlı şeylerin listesi.
Esas olarak Sybase kullanıyoruz, ancak tavsiyelerin çoğu yönetim kurulu genelinde geçerli olacak.

Örneğin SQL Server, bir dizi performans izleme / ayarlama bitiyle birlikte gelir, ancak bunun gibi bir şeye sahip değilseniz (ve belki varsa bile), o zaman aşağıdakileri dikkate alırım ...

Gördüğüm sorunların% 99'u bir birleşime çok fazla tablo koymaktan kaynaklanıyor . Bunun çözümü, birleştirmenin yarısını yapmak (bazı tablolarla) ve sonuçları geçici bir tabloda önbelleğe almaktır. Ardından, bu geçici tabloya katılarak sorgunun geri kalanını yapın.

Sorgu Optimizasyonu Kontrol Listesi

  • Temel tablolarda UPDATE STATISTICS'i çalıştırın
    • Birçok sistem bunu planlanmış haftalık bir iş olarak çalıştırır
  • Temel tablolardan kayıtları silin (muhtemelen silinen kayıtları arşivleyin)
    • Bunu günde bir veya haftada bir kez otomatik olarak yapmayı düşünün.
  • Dizinleri Yeniden Oluşturun
  • Tabloları Yeniden Oluşturma (bcp veri çıkışı / girişi)
  • Veritabanını boşaltın / yeniden yükleyin (ciddi, ancak bozulmayı düzeltebilir)
  • Yeni, daha uygun dizin oluşturun
  • Veritabanında olası bir bozulma olup olmadığını görmek için DBCC'yi çalıştırın
  • Kilitler / Kilitlenmeler
    • Veritabanında başka işlemlerin çalışmadığından emin olun
      • Özellikle DBCC
    • Satır veya sayfa düzeyinde kilitleme kullanıyor musunuz?
    • Sorguya başlamadan önce tabloları özel olarak kilitleyin
    • Tüm işlemlerin tablolara aynı sırayla erişip erişmediğini kontrol edin
  • Endeksler uygun şekilde kullanılıyor mu?
    • Birleştirmeler yalnızca her iki ifade de tam olarak aynı veri türündeyse indeksi kullanır
    • Dizin, yalnızca dizindeki ilk alan (lar) sorguda eşleşirse kullanılır
    • Uygun yerlerde kümelenmiş indeksler kullanılıyor mu?
      • menzil verileri
      • Değer1 ve değer2 arasındaki WHERE alanı
  • Küçük Birleşimler Güzel Birleşimlerdir
    • Varsayılan olarak, iyileştirici bir seferde yalnızca tablo 4'ü dikkate alır.
    • Bu, 4'ten fazla tabloyla birleştirildiğinde optimum olmayan bir sorgu planı seçme şansının yüksek olduğu anlamına gelir.
  • Birleşimi ayırın
    • Birleşimi bölebilir misin?
    • Yabancı anahtarları geçici bir tabloya önceden seçin
    • Birleştirmenin yarısını yapın ve sonuçları geçici bir tabloya koyun
  • Doğru türde geçici masa mı kullanıyorsunuz?
    • #temptablolar, @tablebüyük hacimli (binlerce satır) değişkenlerden çok daha iyi performans gösterebilir .
  • Özet Tablolarını Koru
    • Temel tablolardaki tetikleyicilerle derleyin
    • Günlük / saatlik / vb. Oluşturun
    • Geçici oluşturun
    • Aşamalı olarak oluşturun veya parçalayın / yeniden oluşturun
  • SET SHOWPLAN ON ile sorgu planının ne olduğunu görün
  • SET STATS IO ON ile gerçekte neler olduğunu görün
  • Pragma kullanarak bir dizini zorlayın: (dizin: myindex)
  • SET FORCEPLAN ON kullanarak tablo sırasını zorlayın
  • Parametre Koklama:
    • Depolanan Prosedürü 2'ye Böl
    • proc1'den proc2'yi çağırın
    • @parametresi proc1 tarafından değiştirildiyse optimizer'ın proc2'de dizin seçmesine izin verir
  • Donanımınızı geliştirebilir misiniz?
  • Kaçta koşuyorsun Daha sessiz bir zaman var mı?
  • Çoğaltma Sunucusu (veya diğer kesintisiz süreç) çalışıyor mu? Onu askıya alabilir misin? Örneğin çalıştırın. saatlik?

2
hangi parçasından bahsediyorsun?
AJ.

2
Bu harika şeyler, ama bazı iddialar için bazı referansların olmasını isterdim. Örneğin: Optimizasyonun bir birleştirmede her seferinde yalnızca 4 tabloyu değerlendirdiğini hiç duymamıştım. Bunun nasıl doğru olabileceğini anlamıyorum. Bunun için özellikle bazı referanslar verebilir misiniz? Bunu nereden aldığını görmek isterim.
SheldonH

19
  1. Sorguyu kafanızda çalıştırmanın en iyi yolu hakkında oldukça iyi bir fikriniz olsun.
  2. Sorgu planını kontrol edin - her zaman.
  3. İSTATİSTİKLERİ açın, böylece hem GÇ hem de CPU performansını inceleyebilirsiniz. Sorgu süresine değil, bu sayıları azaltmaya odaklanın (bu, diğer etkinliklerden, önbellekten vb. Etkilenebileceği için).
  4. Bir operatöre gelen çok sayıda satır, ancak çıkan küçük sayılar arayın. Genellikle, bir dizin, gelen satırların sayısını sınırlayarak yardımcı olur (bu, disk okumalarını kaydeder).
  5. Önce en büyük maliyet alt ağacına odaklanın. Bu alt ağacı değiştirmek, çoğu zaman tüm sorgu planını değiştirebilir.
  6. Gördüğüm yaygın sorunlar şunlardır:
    • Çok fazla birleştirme varsa, bazen Sql Server birleşimleri genişletmeyi seçer ve ardından WHERE yan tümcelerini uygular. Bunu genellikle WHERE koşullarını JOIN yan tümcesine veya koşulların satır içine alındığı türetilmiş bir tabloya taşıyarak düzeltebilirsiniz. Görünümler aynı sorunlara neden olabilir.
    • Optimal olmayan birleşimler (LOOP, HASH, MERGE). Benim temel kuralım, üst satırın alt satıra kıyasla çok az satıra sahip olduğu durumlarda bir LOOP birleşimi, setler kabaca eşit ve sıralı olduğunda bir MERGE ve diğer her şey için bir HASH kullanmaktır. Bir birleştirme ipucu eklemek teorinizi test etmenize izin verecektir.
    • Parametre koklama. Depolanan proc'u ilk başta gerçekçi olmayan değerlerle çalıştırdıysanız (örneğin, test için), önbelleğe alınan sorgu planı üretim değerleriniz için yetersiz olabilir. RECOMPILE İLE tekrar çalıştırmak bunu doğrulamalıdır. Bazı saklanan işlemler için, özellikle de farklı boyut aralıklarıyla ilgilenenler için (örneğin, bugün ile dün arasındaki tüm tarihler - ki bu bir DİZİN ARAMASI gerektirir) veya geçen yıl ile bu yıl arasındaki tüm tarihler - bu bir INDEX SCAN ile daha iyi olacaktır. ) her seferinde RECOMPILE İLE çalıştırmanız gerekebilir.
    • Hatalı girinti ... Tamam, bu yüzden Sql Sunucusunun bununla ilgili bir sorunu yok - ancak biçimlendirmeyi düzeltene kadar bir sorguyu anlamayı imkansız buluyorum.

1
Kötü girintinin dahil edilmesi için +1. Biçimlendirme anahtardır! :)
mwigdahl

18

Biraz konu dışı ama bu konular üzerinde kontrolünüz varsa ...
Yüksek Düzey ve Yüksek Etki.

  • Yüksek IO ortamları için disklerinizin RAID 10 veya RAID 0 + 1 veya raid 1 ve raid 0'ın bazı iç içe uygulamaları için olduğundan emin olun.
  • 1500K'dan küçük sürücüleri kullanmayın.
  • Disklerinizin yalnızca Veritabanınız için kullanıldığından emin olun. IE, işletim sistemi kaydı yok.
  • Otomatik büyütme veya benzer özelliği kapatın. Veritabanının beklenen tüm depolamayı kullanmasına izin verin. Şu anda kullanılmakta olanın mutlaka olması gerekmez.
  • tür sorguları için şema ve dizinler tasarlayın.
  • günlük türü bir tablodaysa (yalnızca ekleyin) ve DB'de olması gerekiyorsa onu indekslemeyin.
  • Raporlama payınız varsa (birçok birleştirme ile karmaşık seçimler), o zaman bir yıldız veya kar tanesi şeması ile bir veri ambarı oluşturmaya bakmalısınız.
  • Verileri performans karşılığında kopyalamaktan korkmayın!

8

CREATE INDEX

Sizin WHEREve JOINcümlecikleriniz için mevcut indeksler olduğundan emin olun . Bu, veri erişimini büyük ölçüde hızlandıracaktır.

Ortamınız bir veri reyonu veya ambar ise, akla gelebilecek hemen her tür sorgu için dizinler bol miktarda bulunmalıdır.

Bir de işlem ortamında bu indeks bakım kaynaklarını aşağı sürükleyin değil böylece indekslerin sayısı alt ve bunların tanımları daha stratejik olmalıdır. (Dizin bakımı, bir dizinin yapraklarının, INSERT, UPDATE,ve DELETEişlemlerinde olduğu gibi temel tablodaki bir değişikliği yansıtacak şekilde değiştirilmesi gerektiğidir .)

Ayrıca, dizindeki alanların sırasına dikkat edin - bir alan ne kadar seçici (daha yüksek kardinalite) ise, dizinde o kadar erken görünmelidir. Örneğin, kullanılmış otomobilleri sorguladığınızı varsayalım:

SELECT   i.make, i.model, i.price
FROM     dbo.inventory i
WHERE    i.color = 'red'
  AND    i.price BETWEEN 15000 AND 18000

Fiyat genellikle daha yüksek kardinaliteye sahiptir. Yalnızca birkaç düzine renk mevcut olabilir, ancak büyük olasılıkla binlerce farklı fiyat soruyor.

Bu dizin seçeneklerinden, idx01sorguyu tatmin etmek için daha hızlı yol sağlar:

CREATE INDEX idx01 ON dbo.inventory (price, color)
CREATE INDEX idx02 ON dbo.inventory (color, price)

Bunun nedeni, renk seçiminden daha az arabanın fiyat noktasını karşılaması ve sorgu motoruna analiz edilecek çok daha az veri vermesidir.

Birinde sorguları (ad, soyad) ve diğerinde (soyad, ad) hızlandırmak için yalnızca alan sıralamasında farklılık gösteren çok benzer iki dizine sahip olduğum biliniyor.


6

Yakın zamanda öğrendiğim bir numara, SQL Server'ın bir güncelleme ifadesinde yerel değişkenleri ve alanları güncelleyebilmesidir.

UPDATE table
SET @variable = column = @variable + otherColumn

Veya daha okunaklı versiyon:

UPDATE table
SET
    @variable = @variable + otherColumn,
    column = @variable

Bunu, yinelemeli hesaplamaları uygularken karmaşık imleçleri / birleştirmeleri değiştirmek için kullandım ve ayrıca performansta çok şey kazandım.

Performansta harika iyileştirmeler yapan ayrıntılar ve örnek kod: http://geekswithblogs.net/Rhames/archive/2008/10/28/calculating-running-totals-in-sql-server-2005---the-optimal. aspx


5

Burada MySQL olduğunu varsayarsak, sorguda neler olup bittiğini öğrenmek için EXPLAIN kullanın, dizinlerin olabildiğince verimli kullanıldığından emin olun ve dosya sıralarını ortadan kaldırmaya çalışın. High Performance MySQL: Optimization, Backups, Replication ve More , MySQL Performance Blog'da olduğu gibi bu konuda harika bir kitaptır .


3
Bu MySQL için iyidir, ancak soru "sqlserver" olarak etiketlendi. Yine de bunu yapmak iyi bir şey. SSMS'de yapılacak benzer şey, "Tahmini Yürütme Planını Göster" ve "Gerçek Yürütme Planını Dahil Et" kullanmaktır. Büyük tablo taramalarını ortadan kaldırabilir ve kümelenmiş dizin aramalarını kullanabilirseniz, o zaman en iyi performansa giden yoldasınız demektir.
eksortso

5

@Terrapin isnull ve coalesce arasında bahsetmeye değer birkaç fark daha var (benim için önemli olan ANSI uyumluluğunun yanı sıra).

Coalesce ve IsNull


3

Bazen SQL Server'da bir VEYA'yı bir where cümlesinde kullanırsanız, performansı gerçekten artıracaktır. VEYA'yı kullanmak yerine sadece iki seçim yapın ve bunları bir araya getirin. 1000x hızda aynı sonuçları alırsınız.


Bu açıklanamayan davranışı gördüm.
Esen

2

Where cümlesine bakın - dizinlerin kullanımını doğrulayın / aptalca hiçbir şeyin yapılmadığını doğrulayın

where SomeComplicatedFunctionOf(table.Column) = @param --silly

2

Genelde birleşimlerle başlayacağım - her birini teker teker sorgudan çıkaracağım ve sorun yaşadığım belirli bir birleşim varsa bir fikir edinmek için sorguyu yeniden çalıştıracağım.


2

Tüm geçici tablolarımda, indeksler yapmak için benzersiz kısıtlamalar (uygun olduğunda) ve birincil anahtarlar (neredeyse her zaman) eklemeyi seviyorum.

declare @temp table(
    RowID int not null identity(1,1) primary key,
    SomeUniqueColumn varchar(25) not null,
    SomeNotUniqueColumn varchar(50) null,
    unique(SomeUniqueColumn)
)

2

Her zaman bağlama değişkenlerini kullanmayı alışkanlık haline getirdim. RDBMS SQL ifadelerini önbelleğe almazsa, olası bağlama değişkenleri yardımcı olmaz. Ancak bağlama değişkenlerini kullanmazsanız, RDBMS'nin sorgu yürütme planlarını ve ayrıştırılmış SQL ifadelerini yeniden kullanma şansı yoktur. Tasarruf muazzam olabilir: http://www.akadia.com/services/ora_bind_variables.html . Çoğunlukla Oracle ile çalışıyorum, ancak Microsoft SQL Server hemen hemen aynı şekilde çalışıyor.

Tecrübelerime göre, bağlama değişkenlerini kullanıp kullanmadığınızı bilmiyorsanız, muhtemelen kullanmıyorsunuzdur. Uygulama diliniz bunları desteklemiyorsa, destekleyen bir tane bulun. Bazen B sorgusu için bağlama değişkenlerini kullanarak A sorgusunu düzeltebilirsiniz.

Bundan sonra, RDBMS'ye en çok neyin neden olduğunu bulmak için DBA'mızla konuşuyorum. "Bu sorgu neden yavaş?" Diye sormamanız gerektiğini unutmayın. Bu, doktorunuzdan ekinizi çıkarmasını istemek gibi bir şey. Sorgunuz sorun olabilir, ancak muhtemelen başka bir şeylerin ters gitmesi muhtemeldir. Geliştiriciler olarak, kod satırları açısından düşünme eğilimindeyiz. Bir çizgi yavaşsa, o satırı düzeltin. Ancak bir RDBMS gerçekten karmaşık bir sistemdir ve yavaş sorgunuz çok daha büyük bir sorunun belirtisi olabilir.

Çok fazla SQL ayarlama ipucu, kargo kült idolleri. Çoğu zaman sorun, kullandığınız sözdizimiyle ilgisiz veya çok az ilişkilidir, bu nedenle normalde yapabileceğiniz en temiz sözdizimini kullanmak en iyisidir. Ardından, veritabanını ayarlamanın yollarını aramaya başlayabilirsiniz (sorguyu değil). Sözdizimini yalnızca başarısız olduğunda değiştirin.

Herhangi bir performans ayarı gibi, her zaman anlamlı istatistikler toplayın. Ayarladığınız kullanıcı deneyimi olmadığı sürece duvar saati zamanını kullanmayın. Bunun yerine CPU zamanı, getirilen satırlar ve diskten okunan bloklar gibi şeylere bakın. Çoğu zaman insanlar yanlış şeyi optimize eder.


2

İlk adım: Sorgu Yürütme Planına bakın!
TableScan -> kötü
NestedLoop ->
bir NestedLoop arkasında TableScan uyarısı -> DOOM!

İSTATİSTİK IO'YU
AYARLA İSTATİSTİKLERİ AÇMA ZAMANI


2

İLE (NoLock) kullanarak sorgu çalıştırmak benim yerime oldukça standart bir işlemdir. Onlarca gigabaytlık tablolarda sorgu çalıştırmadan yakalanan herkes çıkarılır ve vurulur.


2
Bu, alışkanlıkla değil, mantıklı bir şekilde kullanılmalıdır. Kilitlemek kötü değildir, sadece yanlış anlaşılmıştır.

2

Mümkünse NOT IN sorgularını LEFT OUTER JOINS'e dönüştürün. Örneğin, Tablo1'de bir yabancı anahtar tarafından kullanılmayan tüm satırları Tablo2'de bulmak istiyorsanız, şunu yapabilirsiniz:

SELECT *
FROM Table1
WHERE Table1.ID NOT IN (
    SELECT Table1ID
    FROM Table2)

Ancak bununla çok daha iyi performans elde edersiniz:

SELECT Table1.*
FROM Table1
LEFT OUTER JOIN Table2 ON Table1.ID = Table2.Table1ID
WHERE Table2.ID is null

1

@ DavidM

Burada MySQL varsayarsak, sorguda neler olup bittiğini öğrenmek için EXPLAIN kullanın, dizinlerin olabildiğince verimli kullanıldığından emin olun ...

SQL Server'da, yürütme planı size aynı şeyi sağlar - hangi dizinlerin vurulduğunu vb. Söyler.


1

Tabloları filtrelediğiniz clm (ler) e göre dizine ekleyin


1

Mutlaka bir SQL performans hilesi değil, kesinlikle ilişkili:

Önceden derlenmiş verileri veritabanından almak yerine doğrudan bellekten almak çok daha hızlı olacağından, mümkün olduğunda memcached'i kullanmak iyi bir fikir olabilir. Ayrıca yerleşik olarak memcached yapılan bir MySQL çeşidi de var (üçüncü taraf).


1

Dizin uzunluklarınızın olabildiğince küçük olduğundan emin olun. Bu, DB'nin dosya sisteminden bir seferde daha fazla anahtar okumasına izin verir, böylece birleşimlerinizi hızlandırır. Bunun tüm DB'lerle çalıştığını varsayıyorum, ancak bunun MySQL için özel bir öneri olduğunu biliyorum.


1

Bakıyorum:

  • Herhangi bir CURSOR döngüsünü açın ve küme tabanlı UPDATE / INSERT deyimlerine dönüştürün.
  • Şu özelliklere sahip herhangi bir uygulama kodunu arayın:
    • Büyük bir kayıt kümesi döndüren bir SP çağırır,
    • Daha sonra uygulamada, her kayıttan geçer ve kayıtları güncellemek için parametrelerle birlikte bir SP çağırır.
    • Bunu, tüm işi tek bir işlemde yapan bir SP'ye dönüştürün.
  • Çok sayıda dize işleme yapan herhangi bir SP. Verilerin doğru yapılandırılmadığının / normalleştirilmediğinin kanıtıdır.
  • Tekerleği yeniden icat eden herhangi bir SP.
  • Bir dakika içinde ne yapmaya çalıştığını anlayamadığım herhangi bir SP!

1
SET NOCOUNT ON

Gerçekten kullanmam gerekmedikçe, genellikle depolanan prosedürlerimin içindeki ilk satır @@ROWCOUNT.


2
@@ ROWCOUNT yine de ayarlandı. NOCOUNT, "etkilenen xx satırları" ifadelerini devre dışı bırakır.
Sklivvz

Bu gerçekten performansta kayda değer bir fark yaratır mı?
JohnFx

Evet, o zaman bir SQL ifadesi her çalıştırıldığında sayı otomatik olarak hesaplanmaz. Fark yarattığını görmek için bir sorguyu karşılaştırmak yeterince kolaydır.
travis

Sayım yine de SQL Server'da izlenir. Gördüğünüz herhangi bir performans farkı, sayımların ağ üzerinden ön ucunuza gitmesi gerektiğidir. Tek bir SEÇME yapıyorsanız, kayda değer bir fark yaratmayacaktır. 100000 ekli bir döngünüz varsa, ağ üzerinden çok fazladır.
Tom H

1

SQL Server'da nolock yönergesini kullanın. Select komutunun beklemek zorunda kalmadan tamamlanmasını sağlar - genellikle diğer işlemlerin tamamlanması.

SELECT * FROM Orders (nolock) where UserName = 'momma'

3
NOLOCK yalnızca doğru sonuçları umursamadığınız sorgular içindir
Mark Sowul

1

Gerekli olmayan yerlerde imleçleri kaldırın.


Evet, imleçler bir lanettir! ;)
Sklivvz

8
Ugh. Bunu böyle niteliksiz olarak atmayın. İmleçler silah gibidir. Kendi başlarına kötü değiller, sadece insanlar onlarla gerçekten kötü şeyler yapıyorlar.
JohnFx

1

Çok sayıda satırın işlevi çağıracağı Sprocs'taki işlev çağrılarını kaldırın.

Meslektaşım çok geniş kayıt kümeleri döndürmek için işlev çağrıları kullandı (örnek olarak userid'den lastlogindate alıyor).

Optimizasyonla görevlendirilen sproc'taki işlev çağrılarını işlevin koduyla değiştirdim: Birçok sprocs'un çalışma süresini> 20 saniyeden <1'e düşürdüm.


0
  • Tüm tabloların önüne dbo ekleyin. yeniden derlemeleri önlemek için.
  • Sorgu planlarını görüntüleyin ve tablo / dizin taramaları için arama yapın.
  • 2005 yılında, eksik dizinler için yönetim görüşlerini araştırın.


0

Depolanan Prosedür adlarının önüne "sp_" koymayın çünkü sistem prosedürlerinin tümü "sp_" ile başlar ve SQL Server, çağrıldığında prosedürünüzü bulmak için daha fazla arama yapmak zorunda kalacaktır.


1
Bunu gerçekten kıyasladınız mı? SQL Server makul olanı yapıyorsa (Depolanan Proc'u bulmak için bir karma algoritma kullanarak), bu hiçbir fark yaratmaz. SQL Server Aslında değildi bunu yaparken, (o muhtemelen vardır kendi procs çağırır beri) sistem performansını kıyameti olur gibi görünüyor.
John Stauffer

1
Bunun erken optimizasyon kovasına düştüğünü düşünüyorum. İnsanların
kafasını

0

Kirli okumalar -

set transaction isolation level read uncommitted

İşlem bütünlüğünün kesinlikle gerekli olmadığı durumlarda (bu genellikle doğrudur) ölü kilitleri önler


1
Evet, ancak bu, bulunması ÇOK zor olan tuhaf hatalara yol açabilir.
Grant Johnson

0

Her zaman önce SQL Profiler'a (çok sayıda iç içe geçme düzeyi olan bir saklı yordamsa) veya sorgu yürütme planlayıcısına (yuvalama içermeyen birkaç SQL deyimiyse) gidiyorum. Zamanın% 90'ında bu iki araçtan biriyle sorunu hemen bulabilirsiniz.

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.