En yaygın SQL anti-paternleri nelerdir? [kapalı]


232

İlişkisel veritabanlarıyla çalışan hepimiz SQL'in farklı olduğunu öğrendik (veya öğrendik). İstenen sonuçları elde etmek ve bunu verimli bir şekilde yapmak, kısmen tanıdık paradigmaları öğrenmek ve en tanıdık programlama kalıplarımızdan bazılarının burada çalışmadığını bulmakla sıkıcı bir süreç içerir. Gördüğünüz (veya kendiniz taahhüt ettiğiniz) ortak antipatterns nedir?


Bu, Yığın Taşması için ne tür bir sorunun uygun olduğuna dair daha yeni standartlara uymayan bir sorudur. Sorulduğunda, bu doğru olmayabilir.
David Manheim

@casperOne, bu soruyu kabul edilebilirliğe dönüştürecek bazı "tarihsel önem" maddesi yok mu?
Amy B

26
Wohole bölgesinde en yararlı sorulardan birinin yapıcı değil olarak kapalı olması üzücü.
HLGEM

11
@HLGEM Kesinlikle katılıyorum. Bu soru Stack Exchange ile yanlış hepsinden mükemmel bir örneğidir
Kevin Morse

1
Konu kesinlikle önemli ve konuyla ilgilidir. Ancak soru çok açık uçlu, bu yüzden cevapların her biri ayrı bir mühendisin kişisel anti-desen hata ayıklamasını anlatıyor.
Shane

Yanıtlar:


156

Çoğu programcının UI-mantığını veri erişim katmanında karıştırma eğilimi beni sürekli olarak hayal kırıklığına uğrattı:

SELECT
    FirstName + ' ' + LastName as "Full Name",
    case UserRole
        when 2 then "Admin"
        when 1 then "Moderator"
        else "User"
    end as "User's Role",
    case SignedIn
        when 0 then "Logged in"
        else "Logged out"
    end as "User signed in?",
    Convert(varchar(100), LastSignOn, 101) as "Last Sign On",
    DateDiff('d', LastSignOn, getDate()) as "Days since last sign on",
    AddrLine1 + ' ' + AddrLine2 + ' ' + AddrLine3 + ' ' +
        City + ', ' + State + ' ' + Zip as "Address",
    'XXX-XX-' + Substring(
        Convert(varchar(9), SSN), 6, 4) as "Social Security #"
FROM Users

Normalde, programcılar bunu yaparlar çünkü veri kümelerini doğrudan bir ızgaraya bağlamak isterler ve SQL Server biçiminin sunucu tarafında istemcideki biçimden daha kullanışlı olması yeterlidir.

Yukarıda gösterilene benzer sorgular son derece kırılgandır çünkü veri katmanını UI katmanıyla sıkıca birleştirirler. Bunun da ötesinde, bu programlama tarzı saklı yordamların yeniden kullanılabilir olmasını tamamen önler.


10
Mümkün olan en fazla sayıda katman / soyutlama katmanında maksimum bağlantı için iyi bir poster-çocuk modeli.
dkretz

3
Performans nedenlerinden dolayı bu tür şeyleri sık sık yaptığım için, SQL Server tarafından yapılan yinelemeli değişiklikler orta düzeydeki kod tarafından yapılanlardan daha hızlı olsa da, eşleştirme için iyi olmayabilir. Size yeniden kullanılabilirlik noktası almıyorum - SP'yi çalıştırmanızı ve isterseniz sütunları yeniden adlandırmanızı hiçbir şey durduramaz.
Joe Pineda

54
Benim favorim insanlar HTML ve javascript yerleştirdiklerinde, örneğin SELECT '<a href=... onclick="">' + ad '</a>'
Matt Rogish

15
Bunun gibi sorgularla, bir web sitesindeki ızgarayı basit bir değiştirme ifadesiyle düzenleyebilirsiniz. Veya dışa aktarmanın içeriğini değiştirin veya rapordaki bir tarihi yeniden biçimlendirin. Bu müşterileri mutlu ediyor ve bana zaman kazandırıyor. Bu yüzden teşekkürler, ama hayır, teşekkürler, böyle sorgulara bağlı kalacağım.
Andomar

4
@Matt Rogish - İsa, birisi bunu yapıyor mu?
Axarydax

118

İşte ilk 3'üm.

Sayı 1. Alan listesi belirtilemedi. (Düzenleme: karışıklığı önlemek için: bu bir üretim kodu kuralıdır. Bir kerelik analiz komut dosyaları için geçerli değildir - yazar olmadıkça.)

SELECT *
Insert Into blah SELECT *

olmalı

SELECT fieldlist
Insert Into blah (fieldlist) SELECT fieldlist

Sayı 2. Bir imleç ve while döngüsü kullanarak, loop değişkenli bir while döngüsü yapacağız.

DECLARE @LoopVar int

SET @LoopVar = (SELECT MIN(TheKey) FROM TheTable)
WHILE @LoopVar is not null
BEGIN
  -- Do Stuff with current value of @LoopVar
  ...
  --Ok, done, now get the next value
  SET @LoopVar = (SELECT MIN(TheKey) FROM TheTable
    WHERE @LoopVar < TheKey)
END

Sayı 3. Dize türleri aracılığıyla DateLogic.

--Trim the time
Convert(Convert(theDate, varchar(10), 121), datetime)

Olmalı

--Trim the time
DateAdd(dd, DateDiff(dd, 0, theDate), 0)

Yakın zamanda "Bir sorgu ikiden daha iyi, amiright?"

SELECT *
FROM blah
WHERE (blah.Name = @name OR @name is null)
  AND (blah.Purpose = @Purpose OR @Purpose is null)

Bu sorgu, parametrelerin değerlerine bağlı olarak iki veya üç farklı yürütme planı gerektirir. Bu sql metni için yalnızca bir yürütme planı oluşturulur ve önbelleğe yapıştırılır. Bu plan parametrelerin değerine bakılmaksızın kullanılacaktır. Bu, kesintili düşük performans ile sonuçlanır. İki sorgu (amaçlanan yürütme planı başına bir sorgu) yazmak çok daha iyidir.


7
hmmm, sadece 2. ve 3. puanlar için +1 vereceğim, ancak geliştiriciler kural 1'i abartıyor. Bazen yeri var.
annakata

1
# 1'in ardındaki mantık nedir?
jalf

29
Select * seçeneğini kullandığınızda, tablodaki her şeyi alırsınız. Bu sütunlar adları ve sırayı değiştirebilir. İstemci kodu genellikle adlara ve siparişe dayanır. Her 6 ayda bir, bir tabloyu değiştirirken sütun sırasının nasıl korunacağı sorulur. Kural takip edilirse önemli olmaz.
Amy B

Bazen # 2 kullandım, diğerleri imleç yoluna gittim (o zaman ilk önce sorgunun sonuçlarını bir tabloya kaydederim, imleci açın). Birisinin her ikisinin de performans testini yapıp yapmadığını hep merak ettim.
Joe Pineda

4
... ancak tabii ki imleçler, set tabanlı SQL ile işin nasıl yapılacağını anlayamadıktan sonra neredeyse her zaman son çare olmalıdır. Bir keresinde, büyük bir geçici tabloyu doldurduktan sonra geçici bir tabloyu arayana geri seçen saklı bir prosedürde (çürük şeyin şemalarını çizdi) korkunç, devasa bir PL / SQL imlecini dikkatlice inceleyerek yaklaşık 45 dakika geçirdim. bildiri. Önemli donanımlarla çalıştırmak 8.5 dakika sürdü. Her şeyi çizdikten sonra, aynı sonuçları 2 saniyenin altında döndüren tek bir sorgu ile değiştirebildim. İmleçler, adam ...
Craig

71
  • Okunabilir parola alanları , örn. Kendini açıklayıcı.

  • Dizinlenmiş sütunlara karşı LIKE kullanma ve neredeyse genel olarak LIKE demeyi tercih ediyorum.

  • SQL tarafından üretilen PK değerlerinin geri dönüşümü.

  • Henüz kimse tanrı masasından bahsetmedi . Hiçbir şey 100 organik bit bayrağı, büyük dize ve tamsayı gibi "organik" demez.

  • Sonra ".ini dosyalarını özlüyorum" deseni var: CSV'leri, sınırlandırılmış dizeleri veya diğer ayrıştırılmış verileri büyük metin alanlarında saklamak.

  • Ve MS SQL sunucusu için hiç imleç kullanımı . Herhangi bir imleç görevini yapmanın daha iyi bir yolu var.

Düzenlendi çünkü çok fazla var!


19
imleçler hakkında yanlış, herhangi bir şey yapmak% 100 doğru veya% 100 yanlış olduğunu söyleyerek tereddüt olurdu
Shawn

4
Şimdiye kadar gördüğüm her imleç savunma örneği iş için yanlış aracı kullanıyor. Ancak bildiğiniz tek şey SQL ise, onu uygun olmayan şekilde kullanırsınız veya başka tür yazılımlar yazmayı öğrenirsiniz.
dkretz

3
@tuinstoel: '% blah%' LIKE bir dizini nasıl kullanacak? Dizin oluşturma, sıralamaya dayanır ve bu örnek, bir dizenin rastgele orta konumunu arar. (1. karakter
1'in dizini sıralar

12
Çoğu veritabanı sunucusunda (en azından kullandıklarım), LIKE dizinleri kullanabilir. arama dizesinde önce gelir. Sanırım burada biraz çapraz amaçlardan bahsediyor olabilirsiniz.
Cowan

10
Beğenmediğin gibi LIKE '%LIKE'.
Johan

62

Bunun için derinlemesine araştırma yapmak zorunda değilsiniz: Hazırlanmış ifadeler kullanmamak.


3
Evet. Deneyimlerime göre, "hataları yakalamamak" ile aynı bağlamda yakından takip ettim.
dkretz

1
@stesch: Bu, görünümleri kullanmak ve değişken bir raporlama tarihine sahip olmaktan başka bir şey değildir. Değişken bir raporlama tarihi varsa (çoğu uygulama var sanırım) görünümler bir antipattern vardır. Bunu ayrı bir cevapta eklerdim, ama maalesef kapalı.
Stefan Steiger

56

Anlamsız tablo takma adları kullanma:

from employee t1,
department t2,
job t3,
...

Büyük bir SQL ifadesini okumayı olması gerekenden çok daha zor hale getirir


49
adlar? cehennem gibi gerçek sütun isimlerini gördüm
annakata

10
kısa takma adlar TAMAM. Anlamlı bir ad istiyorsanız, diğer ad kullanmayın.
Joel Coehoorn

43
"Kısa" demedi, "anlamsız" dedi. Kitabımda e, d ve j'yi örnek sorgudaki takma adlar olarak kullanmanın yanlış bir yanı yoktur.
Robert Rossney

11
Kesinlikle, Robert - e, d ve j benimle iyi olur.
Tony Andrews

8
Emp için çalışan, dep ve iş için dep (veya belki jb) :)
kullanacağım

53
var query = "select COUNT(*) from Users where UserName = '" 
            + tbUser.Text 
            + "' and Password = '" 
            + tbPassword.Text +"'";
  1. Körü körüne güvenen kullanıcı girişi
  2. Kullanmama parametreli sorgular
  3. Açık metin şifreleri

Bunların tümü, bazı (herhangi) türden bir veritabanı abstracton katmanı kullanılarak yararlı bir şekilde ele alınabilir.
dkretz

@doofledorfer: Katılıyorum, böyle bir durumda orta katman kesinlikle daha iyi olurdu, ayrıca hoş bir yan etki olarak önbellekleme sonuçları sağlar.
Joe Pineda

Harika bir örnek. Bir geliştirici bunu iyi bir çözümle nasıl değiştirirse, iyi bir SQL geliştiricisi olmanın yarı yoludur.
Steve McLeod

46

Benim ayılar benim Yönetici Direktörü en iyi arkadaş köpek damat ve 8 yaşındaki oğlu tarafından bir araya getirilmiş 450 sütun Erişim tabloları ve sadece birileri bir veri yapısını düzgün bir şekilde normalleştirmek için nasıl bilmiyorum çünkü var.

Genellikle, bu arama tablosu şöyle görünür:

ID INT,
İsim NVARCHAR (132),
IntValue1 INT,
IntValue2 INT,
CharValue1 NVARCHAR (255),
CharValue2 NVARCHAR (255),
Tarih1 DATETIME,
Tarih2 DATETIME

Bu tür iğrençliklere dayanan sistemlere sahip gördüğüm müşteri sayısını kaybettim.


1
Daha da kötüsü, aslında otomatik olarak desteklenen Access'in en yeni sürümünde, bu Value1, Value2, Value3 ... sütun fetichismini daha da teşvik edeceğini okudum
Joe Pineda

Bekle - 8 yaşındaki oğlum köpek bakıcısının oğlu mu?
barrypicker

28

En çok sevmediğim

  1. Tablo, sprocs vb. Oluştururken boşluk kullanma CamelCase veya under_scores ve tekil veya çoğul ve UPPERCASE veya küçük harf ile iyiyim ancak özellikle [garip aralıklıysa] bir tabloya veya sütuna [boşluklarla] başvurmak zorundayım (evet, Bunun içine girdim) gerçekten beni rahatsız ediyor.

  2. Denormalize veriler. Bir tablonun mükemmel bir şekilde normalleştirilmesi gerekmez, ancak mevcut değerlendirme puanları veya birincil şeyleri hakkında bilgi sahibi olan bir çalışanlar tablosuyla karşılaştığımda, muhtemelen bir noktada ayrı bir tablo yapmam gerekeceğini ve sonra onları senkronize tutmaya çalışın. İlk önce verileri normalleştireceğim ve sonra denormalizasyonun yardımcı olduğu bir yer görürsem, dikkate alacağım.

  3. Görünümlerin veya imleçlerin aşırı kullanımı. Görünümlerin bir amacı vardır, ancak her tablo bir görünüme sarıldığında çok fazladır. Birkaç kez imleç kullanmak zorunda kaldım, ancak genellikle bunun için başka mekanizmalar kullanabilirsiniz.

  4. Giriş. Bir program bir anti-desen olabilir mi? İşimde SQL Server var, ancak bazı kişiler teknik olmayan kullanıcılara erişilebilirlik, "kullanım kolaylığı" ve "kolaylık" nedeniyle erişim kullanıyor. Burada girecek çok şey var, ama benzer bir ortamdaysanız, biliyorsunuz.


2
# 4 - sadece <a href=' stackoverflow.com/questions/327199/…> :) için başka bir konu var .
dkretz

4
Erişim bir DBMS DEĞİLDİR. Çok basit bir veritabanı yöneticisi ile birlikte bir RAD ortamı. SQL Server, Oracle ve diğ. olacak asla size dil ve tesis gibi Crystal Reports gibi VB-a eklemek sürece, değiştirin.
Joe Pineda

26

SP'yi saklama yordamı adının öneki olarak kullanın, çünkü önce özel olanlar yerine Sistem yordamları konumunda arama yapar.


1
Ayrıca, tüm saklı yordamlar için başka bir ortak önek kullanmak üzere genişletilebilir ve bu da sıralı bir listeyi seçmeyi zorlaştırır.
dkretz

7
Doofledorfer yorumu için +1! Bunu çok gördüm, bu aptalca buldum ve gerçekten belirli bir SP'yi aramayı çok zorlaştırıyor !!! Ayrıca görünümler için "vw_", tablolar ve benzerleri için "tbl_", nasıl nefret ediyorum!
Joe Pineda

1
Nesneleri dosyalara kodluyorsanız önekler yararlı olabilir (örneğin: kaynak kontrolü, dağıtımlar veya geçiş için)
Rick

1
Saklanan her yordamı sp veya usp ile öneklemek neden yeryüzünde yararlı olur ? İstediğiniz listenin taranmasını zorlaştırır.
Ryan Lundy

25

Geçici tablo ve imleçlerin aşırı kullanımı.


2
"Tek bildiğim prosedür dilleri" olduğuna dair iyi kanıt.
dkretz

2
Herhangi bir şeyin aşırı kullanımı, tanım gereği istenmeyen bir durumdur. Geçici tabloların / imleçlerin kullanılmasının gerekmediği özel bir örnek yardımcı olacaktır.
Jace Rhea

6
Çoğunlukla geçici tabloların az kullanıldığını görüyorum. SQL Server ile genellikle tek bir yekpare sorgu yerine geçici tablolar içeren bir şeyler yaparak performans kazançları elde edersiniz.
Cervo

24

Zaman değerlerini saklamak için sadece UTC saat dilimi kullanılmalıdır. Yerel saat kullanılmamalıdır.


3
Geçmişteki tarihler için UTC'den yerel saate dönüştürmek için iyi bir basit çözüm bulamadım, gün ışığından tasarruf etmenin dikkate alınması gerektiğinde, yıllar ve ülkeler arasında değişen değişiklik tarihleri ​​ve ülkelerdeki tüm istisnalar. Dolayısıyla UTC sizi dönüşüm karmaşıklığından kurtarmaz. Ancak, saklanan her tarih saatinin saat dilimini bilmenin bir yolu olması önemlidir.
ckarras

1
@CsongorHalmai Birçok yer gün ışığından yararlanma pratiği yapar, bu nedenle vardiyadan sonraki bir saat içindeki zaman değerleri belirsiz olabilir.
Frank Schwieterman

Bu, şimdiki zaman ve geçmiş için kesinlikle doğrudur, ancak gelecek için, özellikle de oldukça uzak gelecek için, açık zaman dilimleri genellikle bir zorunluluktur. 2049-09-27T17: 00: 00 New York saatinde yeni yazılmış ve süresi dolan 30 yıllık bir seçeneğiniz varsa, o zaman 21: 00: 00Z olacağını körü körüne kabul edemezsiniz. ABD Kongresi DST kurallarını değiştirebilir. Yerel saati ve gerçek saat dilimini (America / New_York) ayrı tutmalısınız.
John Cowan

23

SCOPE_IDENTITY () yerine @@ IDENTITY kullanılarak

Bu cevaptan alıntı :

  • @@ IDENTITY geçerli oturumdaki herhangi bir tablo için oluşturulan tüm kimlik değerlerini tüm kapsamlarda döndürür. Burada dikkatli olmalısın, çünkü kapsamlar arasında. Geçerli ifadeniz yerine tetikleyiciden bir değer alabilirsiniz.
  • SCOPE_IDENTITY geçerli oturumdaki herhangi bir tablo ve geçerli kapsam için oluşturulan son kimlik değerini döndürür. Genellikle ne kullanmak istiyorsunuz.
  • IDENT_CURRENT , herhangi bir oturumda ve kapsamda belirli bir tablo için oluşturulan son kimlik değerini döndürür. Bu, yukarıdaki ikisi ihtiyacınız olan şey değilse (çok nadir), hangi tablodan değer istediğinizi belirtmenize olanak tanır. Kayıt eklemediğiniz bir tablo için geçerli KİMLİK değerini almak istiyorsanız bunu kullanabilirsiniz.

+1 çok doğru,
ayıklanması

23

'Ölü' bir alanı, amaçlanmadığı bir şey için yeniden kullanmak (örneğin, kullanıcı verilerini bir 'Faks' alanında saklamak) - hızlı bir düzeltme olarak çok cazip!


21
select some_column, ...
from some_table
group by some_column

ve sonucun some_column tarafından sıralanacağını varsayarsak. Bunu varsayımın geçerli olduğu Sybase ile biraz gördüm (şimdilik).


1
sıralama düzenini varsayarak EVV için oy verin, çünkü bir keresinde sorgu aracında gösterilen yol buydu
Joel Coehoorn

3
Hatta bunun bir kereden fazla bir hata olarak rapor edildiğini gördüm.
dkretz

6
MySQL'de sıralamak için belgelenmiştir. < dev.mysql.com/doc/refman/5.0/en/select.html >. Yani MySQL'i suçlayın (tekrar).
derobert

1
Oracle'da, sıralanmamış sonuçlar (neredeyse) 10G sürümüne kadar her zaman gruplandırmayla eşleşti. SİPARİŞ TARAFINDAN dışarıda bırakan geliştiriciler için çok sayıda yeniden çalışma!
Tony Andrews

1
Hatta bunun SQL Server için bir gerçek olarak belirtildiği bir eğitim sınıfındaydım. Gerçekten yüksek sesle protesto etmek zorunda kaldım. Sadece 20 karaktere kaydetmek için belirsiz veya belgesiz davranışlara güveniyorsunuz.
erikkallen

20
SELECT FirstName + ' ' + LastName as "Full Name", case UserRole when 2 then "Admin" when 1 then "Moderator" else "User" end as "User's Role", case SignedIn when 0 then "Logged in" else "Logged out" end as "User signed in?", Convert(varchar(100), LastSignOn, 101) as "Last Sign On", DateDiff('d', LastSignOn, getDate()) as "Days since last sign on", AddrLine1 + ' ' + AddrLine2 + ' ' + AddrLine3 + ' ' + City + ', ' + State + ' ' + Zip as "Address", 'XXX-XX-' + Substring(Convert(varchar(9), SSN), 6, 4) as "Social Security #" FROM Users

Ya da, her şeyi tek bir çizgiye sıkıştırmak.


Bir önceki yorumun sorgusunu kullandım, çünkü bu benim ilk SQL ifademdi.
Jasper Bekkers

17
  • FROM TableA, TableB WHERESözdizimi yerine KATILIYORFROM TableA INNER JOIN TableB ON

  • Bir sorgunun döndürüleceği varsayımlarında, bir ORDER BY deyimi koymadan belirli bir şekilde sıralanmıştır, çünkü bu yalnızca sorgu aracında test sırasında ortaya çıktığı şekildeydi.


5
Oracle DBA'larım her zaman "ANSI birleşimlerini" kullandığımdan, yani doğru yol olarak sunduğunuzdan şikayet ediyor. Ama bunu yapmaya devam ediyorum ve derinlerde bunun daha iyi olduğunu bildiklerinden şüpheleniyorum.
Steve McLeod

1
Oracle'ın standart SQL'in gitmesini dilediğinden şüpheleniyorum. :-) Ayrıca, MySQL 5'te örtük ve açık JOINS'i (diğer adıyla ANSI JOINs) karıştıramazsınız - işe yaramaz. Hangi açık JION'lar için başka bir argüman.
staticsan

3
Bir INNER JOIN B ON bile bir anti-desen olduğunu söyleyebilirim. INNER JOIN B KULLANIMI tercih ederim.
John Nilsson

Oracle şimdi ANSI sözdizimini desteklemektedir, ancak geçmişte dış birleşimler için gerçekten garip bir sözdizimine sahiptiler ve bunu hala kullanan çok fazla insan var.
Cervo


14

Kariyerlerinin ilk altı ayında SQL öğrenmek ve gelecek 10 yıl boyunca hiçbir şey öğrenmemek. Özellikle pencereleme / analitik SQL özelliklerini öğrenmek ya da etkili bir şekilde kullanmamak. Özellikle over () ve by partition kullanımı.

Toplama işlevleri gibi pencere işlevleri, tanımlanmış bir satır kümesinde (grup) bir toplama gerçekleştirir, ancak grup başına bir değer döndürmek yerine, pencere işlevleri her grup için birden çok değer döndürebilir.

Pencereleme işlevlerine güzel bir genel bakış için O'Reilly SQL Yemek Kitabı Ek A'ya bakınız .


12

Sadece listeyi tamamlamak için şu anki favorimi buraya koymam gerekiyor. En sevdiğim antipatternim sorgularınızı test etmiyor .

Bu şu durumlarda geçerlidir:

  1. Sorgunuz birden fazla tablo içeriyor.
  2. Bir sorgu için en uygun tasarıma sahip olduğunuzu düşünüyorsunuz, ancak varsayımlarınızı test etmeye zahmet etmeyin.
  3. Optimize edilmiş olup olmadığına dair hiçbir ipucu olmadan çalışan ilk sorguyu kabul edersiniz.

Ve atipik veya yetersiz verilere karşı yapılan testler dikkate alınmaz. Saklı bir yordamsa, test ifadesini bir yoruma yerleştirin ve sonuçlarıyla birlikte kaydedin. Aksi takdirde, sonuçları kodla birlikte bir yoruma koyun.


Minimal T-SQL testi için çok yararlı bir teknik: SP, UDF vb. END
Joe Pineda

SQL Server, hiçbir zaman yürütülmediği halde, test bloğundaki kodu ayrıştırır. Böylece nesneniz değiştirilip daha fazla parametre veya farklı türde vb. Veya bağlı olduğu bir nesne değiştirildiğinde, yalnızca bir yürütme planı isteyerek bir hata alırsınız!
Joe Pineda

Gerçek verilerle test etmek her zaman mümkün değildir. Genellikle dev sunucusu / "test" sunucusu düşük ücretlidir ve canlı sunucunun bir kısmını alır. Testler genellikle canlı sunucuya karşı yapılır. Bazı yerler daha iyidir ve canlı veriler içeren bir test veya hazırlama sunucusuna sahiptir.
Cervo

11

Geçici Tablo kötüye kullanımı.

Özellikle bu tür şeyler:

SELECT personid, firstname, lastname, age
INTO #tmpPeople
FROM People
WHERE lastname like 's%'

DELETE FROM #tmpPeople
WHERE firstname = 'John'

DELETE FROM #tmpPeople
WHERE firstname = 'Jon'

DELETE FROM #tmpPeople
WHERE age > 35

UPDATE People
SET firstname = 'Fred'
WHERE personid IN (SELECT personid from #tmpPeople)

Bir sorgudan geçici bir tablo oluşturmayın, yalnızca ihtiyacınız olmayan satırları silin.

Ve evet, üretim DB'lerinde bu formda kod sayfaları gördüm.


1
+1, katılıyorum. Her ne kadar bu tekniğin performansı arttırdığı en az bir veya iki vaka buldum - dahil olan sorgular en azını söylemek karmaşıktı.
Ağustos'ta

1
Doğru - sadece her sorguda bir yer var :)
geofftnz

1
Bazen koşullar çok karmaşıksa bunu yapmak zorundasınız. Doğru aşırı istismar edilebilir. Ancak çoğu kez basit bir silme, ilk sorguda vakayı almak için mantıktan çok daha basittir. Ayrıca bazen, cümle işe yaramazsa, ilk sorgu yavaşlar. Ancak sadece daha küçük sıcaklık masasında yapmak daha verimlidir. Ve diğer zamanlarda iş adamları gerçeği sonra eklemek devam vakaları eklemek.
Cervo

9

Aksine görüş: normalleşmeye aşırı takıntı.

Çoğu SQL / RBDB sistemi, normalleştirilmemiş verilerle bile oldukça yararlı olan bir çok özellik (işlem, çoğaltma) sağlar. Disk alanı ucuzdur ve getirilen verileri değiştirmek / filtrelemek / aramak, bazen 1NF şemasını yazmak ve içindeki tüm zorluklarla (karmaşık birleşimler, kötü alt seçimler) uğraşmaktan daha basit (daha kolay kod, daha hızlı geliştirme süresi) olabilir. , vb).

Aşırı normalleştirilmiş sistemlerin, özellikle erken gelişim aşamalarında genellikle erken optimizasyon olduğunu gördüm.

(üzerine daha fazla düşünce ... http://writeonly.wordpress.com/2008/12/05/simple-object-db-using-json-and-python-sqlite/ )


22
Normalleşmemenin genellikle erken optimizasyon olduğunu düşünüyorum.
tuinstoel

Bazen öyle, bazen değil. Neyse ki, genellikle test etmek kolaydır ve farklı seçenekler farklı db ihtiyaçları ile çalışır.
Gregg Lind

17
Normalleştirme sadece disk alanı tasarrufu için değildir. Ayrıca veriler için yetkili bir kaynak oluşturmaktır. Veriler sadece bir yerde saklanırsa, tutarlılık dikkatli kodlamanın bir yan ürünü değil, bunun yerine tasarımın bir yan ürünüdür.
Grant Johnson

Bileşik verileri JSON biçiminde depolamak bir şeydir: daha fazla destek var ve bilinçli bir ödünleşim. Bir birleştirmeyi kaydetmek için virgülle ayrılmış (veya her neyse) değerleri kullanmak, kuruş açısından ve pound-aptalca.
John Cowan

noSQL çözümleri, çok tablolu aramaları ortadan kaldırarak yinelenen verilerin maliyetinde bir performans avantajı göstermektedir. Bütün normalleştirme olayını başına koyar. Bazı örneklerde, bir işlemin mümkün olan en hızlı tepki süresine sahip olmasını sağlamak için veriler birden fazla yerde toplanır. Elbette, yetkili kaynaklar hakkında sorular devreye giriyor.
19'da barrypicker

9

Ben sadece bir araya koymak, burada bazı SQL yanıtları dayalı SO.

Olay işleyicileri OOP için tetikleyicilerin veritabanlarına yönelik olduğunu düşünmek ciddi bir antipatterntir. Tabloda bir işlem (olay) gerçekleştiğinde tetiklenecek yalnızca eski mantığın tetikleyicilere yerleştirilebileceği algısı vardır.

Doğru değil. En büyük farklardan biri, tetikleyicilerin bir intikamla senkronize olmasıdır, çünkü bir satır işleminde değil, ayarlanmış bir işlemde senkronize olurlar. OOP tarafında, tam tersi olaylar, eşzamansız işlemleri gerçekleştirmenin etkili bir yoludur.


8

Herhangi bir yorum yapılmadan Saklı Yordamlar veya İşlevler ...


Ve views;) Tablo değerli işlevler dışında doğru işlevler (= parametrelerle görünümler).
Stefan Steiger

7

1) Bu "resmi" bir anti-desen bilmiyorum, ama ben bir veritabanı sütununda sihirli değer olarak dize değişmezleri sevmiyorum ve kaçınmaya çalışıyorum.

MediaWiki'nin 'image' tablosundan bir örnek:

img_media_type ENUM("UNKNOWN", "BITMAP", "DRAWING", "AUDIO", "VIDEO", 
    "MULTIMEDIA", "OFFICE", "TEXT", "EXECUTABLE", "ARCHIVE") default NULL,
img_major_mime ENUM("unknown", "application", "audio", "image", "text", 
    "video", "message", "model", "multipart") NOT NULL default "unknown",

(Sadece farklı bir kasa fark ettim, kaçınılması gereken başka bir şey)

Int birincil anahtarları ile tablolara ImageMediaType ve ImageMajorMime int aramalar gibi durumlarda tasarlayın.

2) belirli NLS ayarlarına dayanan tarih / dize dönüştürme

CONVERT(NVARCHAR, GETDATE())

biçim tanımlayıcı olmadan


Ve sözdizimsel girinti de yok. Argghh.
dkretz

2
Bu neden kötü? elbette bir değer kümesi ifade etmeye çalışıyorsanız, bu sadece bir arama tablosu gibi çalışır ve onu çağıran kodla daha iyi uyuyor. Kimliği yerine uygulama kodumda bir arama tablosunun belirli satırlarına eşlenen uygulama kodumdaki bir numaradan ziyade DB'mde bir numaralandırma kısıtlamasıyla eşleşen bir numaralandırma var. Sadece daha temiz hissettiriyor.
Jack Ryan

@JackRyan: Bu kötü çünkü numaralandırma listesini daha sonra değiştirdiğinizde, şimdi iki yerde değiştirmeyi hatırlamanız gerekiyor. Bu ihlal DRY . Veritabanı tek hakikat kaynağı olmalıdır.
Gerrat

7

Bir sorgudaki özdeş alt sorgular.


10
Ne yazık ki, bazen bundan kaçınamazsınız - SQL 2000'de "WITH" anahtar kelimesi yoktu ve UDF'leri kullanarak sık sık alt sorguları performans cezalarına yol açıyor, MS'yi suçluyor ...
Joe Pineda

Umarım bu günlerden birini eklemeye çalışırlar.
EvilTeach

SQL 2000'de tablo değişkenlerini kullanabilirsiniz.
özyinelemeli

@recursive: Tablo değişkeninde dizinleri alt sorgudan yavaşlatacak şekilde değiştiremezsiniz. Ancak, özel dizinlerle geçici bir tablo kullanabilirsiniz.
Rick

Harika, SQL ile yıllardır çalışıyor ve hatta Ortak Tablo İfadeleri olduğunu bilmiyordum (onlara ihtiyacım olsa da). Şimdi anladım! Teşekkürler!
sleske

7
  • Değiştirilmiş Görünüm - Çok sık ve önceden haber verilmeden veya gerekçesiz olarak değiştirilen görünüm. Değişiklik ya en uygunsuz zamanda fark edilir ya da daha kötüsü yanlış olur ve asla fark edilmez. Belki biri bu sütun için daha iyi bir ad düşündüğü için başvurunuz kırılacaktır. Kural olarak görüşler, tüketicilerle sözleşme yaparken temel tabloların faydasını genişletmelidir. Sorunları düzeltin, ancak yeni bir görünüm oluşturmak için özellikler veya daha kötü değişiklik davranışı eklemeyin. Azaltmak için görünümleri diğer projelerle paylaşmayın ve platformlar izin verdiğinde CTE'leri kullanın . Mağazanızın bir DBA'sı varsa, muhtemelen görünümleri değiştiremezsiniz, ancak tüm görünümleriniz eski ve bu durumda işe yaramaz olacaktır.

  • Paramed - Bir sorgunun birden fazla amacı olabilir mi? Muhtemelen ama okuyan bir sonraki kişi derin meditasyona kadar bilemez. Şu anda onlara ihtiyacınız olmasa bile, hata ayıklamak için "sadece" olsa bile, şansınız olacaktır. Parametrelerin eklenmesi bakım süresini azaltır ve işleri KURU tutar. Where yan tümcesiniz varsa parametreleriniz olmalıdır.

  • VAKA olmayışı -

    SELECT  
    CASE @problem  
      WHEN 'Need to replace column A with this medium to large collection of strings hanging out in my code.'  
        THEN 'Create a table for lookup and add to your from clause.'  
      WHEN 'Scrubbing values in the result set based on some business rules.'  
        THEN 'Fix the data in the database'  
      WHEN 'Formating dates or numbers.'   
        THEN 'Apply formating in the presentation layer.'  
      WHEN 'Createing a cross tab'  
        THEN 'Good, but in reporting you should probably be using cross tab, matrix or pivot templates'   
    ELSE 'You probably found another case for no CASE but now I have to edit my code instead of enriching the data...' END  

Üçüncü olanı sevdim. Zaten yerel olarak kullanıyorum ...
alphadogg

Sahne için teşekkürler. :)
jason saldo

5

En çok bulduğum ve performans açısından önemli bir maliyeti olabilir:

  • Küme tabanlı ifade yerine imleç kullanma. Programcı doğru düşünürken bu sık sık olur sanırım.

  • Türetilmiş bir tabloya birleştirme işi yapabiliyorsa ilişkili alt sorgular kullanarak.


Ne demek istediğimi düşündüğünüzü kastediyorsanız katılıyorum; ancak ilişkili bir alt sorgu türetilmiş bir tablo IIRC türüdür.
dkretz

1
Türetilmiş bir tablo ayarlanmış bir işlemken, dış sorgudaki her satır için ilişkili bir alt sorgu çalışır ve bu da onu daha az verimli hale getirir (10 üzerinden 9 kez)
Mitch Wheat

Birkaç yıl önce SQL S.'nin ilişkili sorguları işlemek için bir şekilde optimize edildiğini görünce şaşırdım: basit olanlar için bir JOIN kullanarak mantıksal olarak eşdeğer bir sorgu ile aynı yürütme planını alırsınız! Ayrıca, Oracle'ı dizlerine getiren ilişkili sorgular SQL S'de yalnızca yavaş çalışır.!
Joe Pineda

Bu yüzden her zaman her iki şekilde de test ediyorum. Ve genellikle her iki şekilde denerim. Pratikte, SQL Server için, yine de, ilişkili sq yavaş hiçbir yavaş buldum.
dkretz

3
LÜTFEN, ilişkili bir alt sorgunun ve birleştirmenin KİMLİKLİ olduğunu anlayın (çoğu durumda). Birbirlerine göre optimize edilmiş farklı şeyler bile değil, aynı operasyonun sadece farklı metinsel gösterimleri.
erikkallen

5

Geçici tablolara, özellikle SQL Server'dan Oracle'a geçiş yapan kişilerin, geçici tabloları aşırı kullanma alışkanlığı vardır. Yuvalanmış select deyimlerini kullanmanız yeterlidir.


5

SQL uygulamalarını (hem tek tek sorgular hem de çok kullanıcılı sistemler) hızlı veya yavaş kılan şey hakkında iyi bir fikir sahibi olmadan sorgu yazan geliştiriciler. Buna cehalet de dahildir:

  • çoğu sorgunun darboğazının CPU değil I / O olduğu göz önüne alındığında fiziksel I / O minimizasyon stratejileri
  • farklı fiziksel depolama erişim türlerinin mükemmel etkisi (örneğin, fiziksel depolama alanınız SSD ise daha az olsa da, çok sayıda sıralı G / Ç, küçük rastgele G / Ç'den daha hızlı olacaktır!)
  • DBMS zayıf bir sorgu planı oluşturuyorsa bir sorguyu el ile ayarlama
  • kötü veritabanı performansının nasıl teşhis edileceği, yavaş bir sorgunun "hata ayıklanması" ve bir sorgu planının nasıl okunacağı (veya seçtiğiniz DBMS'nize bağlı olarak EXPLAIN)
  • çok kullanıcılı uygulamalarda verimi optimize etmek ve kilitlenmeleri önlemek için kilitleme stratejileri
  • veri kümelerinin işlenmesinde harmanlamanın ve diğer püf noktalarının önemi
  • alanı ve performansı en iyi şekilde dengelemek için tablo ve dizin tasarımı (örn. dizinleri kaplama, dizinleri mümkün olduğunca küçük tutma, veri türlerini gereken minimum boyuta düşürme vb.)

3

SQL'i yüceltilmiş bir ISAM (Dizinlenmiş Sıralı Erişim Yöntemi) paketi olarak kullanma. Özellikle, SQL deyimlerini daha büyük de olsa tek bir deyimde birleştirmek yerine imleçleri iç içe yerleştirmek. Bu aynı zamanda 'optimize ediciyi kötüye kullanma' olarak da sayılır, çünkü aslında optimize edicinin yapabileceği pek bir şey yoktur. Bu, maksimum verimsizlik için hazırlanmamış ifadelerle birleştirilebilir:

DECLARE c1 CURSOR FOR SELECT Col1, Col2, Col3 FROM Table1

FOREACH c1 INTO a.col1, a.col2, a.col3
    DECLARE c2 CURSOR FOR
        SELECT Item1, Item2, Item3
            FROM Table2
            WHERE Table2.Item1 = a.col2
    FOREACH c2 INTO b.item1, b.item2, b.item3
        ...process data from records a and b...
    END FOREACH
END FOREACH

Doğru çözüm (neredeyse her zaman) iki SELECT ifadesini bir araya getirmektir:

DECLARE c1 CURSOR FOR
    SELECT Col1, Col2, Col3, Item1, Item2, Item3
        FROM Table1, Table2
        WHERE Table2.Item1 = Table1.Col2
        -- ORDER BY Table1.Col1, Table2.Item1

FOREACH c1 INTO a.col1, a.col2, a.col3, b.item1, b.item2, b.item3
    ...process data from records a and b...
END FOREACH

Çift döngü versiyonunun tek avantajı, iç döngü sona erdiği için Tablo1'deki değerler arasındaki boşlukları kolayca tespit edebilmenizdir. Bu kontrol sonu raporlarında bir faktör olabilir.

Ayrıca, uygulamada sıralama genellikle hayır-hayır.


Bu sözdizimi olmasa da, stil benim deneyimimde özellikle PHP'de yaygın.
dkretz

Sözdizimi aslında IBM Informix-4GL - ancak açıklama yolunda çok fazla şeye ihtiyaç duymayacak kadar açık (bence). Ve stil, programlama dilinden bağımsız olarak birçok SQL programında yaygındır.
Jonathan Leffler

Antipatterninizi göstermek için iyi bilinen bir antipattern (örtülü birleşimler) kullanmanız dışında, noktayı yener.
Johan

Ve elbette imleçlerin kullanımı bir SQl antipatternidir. Neredeyse tüm imleçler set tabanlı işlemler olarak yeniden yazılabilir. Sadece birkaç yıllık deneyime sahip olan ve veri tabanının iç kısmının nasıl çalıştığını anlayan DBA'ların yazamayacağı türden değil. Hiçbir uygulama geliştiricisinin SQL imleci yazması gerekmez.
HLGEM

3

Birincil anahtarları kayıt adresleri için yedek olarak kullanma ve yabancı anahtarları kayıtlara yerleştirilmiş işaretçiler için bir yedek olarak kullanma.

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.