Apa anti-pola SQL yang paling umum? [Tutup]

232

Kita semua yang bekerja dengan database relasional telah belajar (atau sedang belajar) bahwa SQL berbeda. Menggali hasil yang diinginkan, dan melakukannya dengan efisien, melibatkan proses yang membosankan yang sebagian ditandai dengan mempelajari paradigma yang tidak dikenal, dan menemukan bahwa beberapa pola pemrograman kita yang paling dikenal tidak bekerja di sini. Apa antipatterns umum yang Anda lihat (atau diri Anda berkomitmen)?

le dorfier
sumber
Ini adalah pertanyaan yang tidak sesuai dengan standar yang lebih baru tentang jenis pertanyaan apa yang sesuai untuk Stack Overflow. Ketika ditanya, ini mungkin tidak benar.
David Manheim
@casperOne tidak ada klausul "signifikansi historis" yang akan membuat pertanyaan ini diterima kakek?
Amy B
26
Saya merasa sedih bahwa salah satu pertanyaan paling berguna di situs wohole ditutup karena tidak konstruktif.
HLGEM
11
@HLGEM Saya setuju sepenuhnya. Pertanyaan ini adalah contoh sempurna dari semua yang salah dengan StackExchange
Kevin Morse
1
Topiknya sangat penting dan relevan. Tetapi pertanyaannya terlalu terbuka sehingga mengapa masing-masing jawaban menggambarkan bugbear anti-pola pribadi seorang insinyur individu.
Shane

Jawaban:

156

Saya secara konsisten kecewa dengan kecenderungan kebanyakan programmer untuk mencampurkan logika UI mereka di lapisan akses data:

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

Biasanya, programmer melakukan ini karena mereka berniat untuk mengikat dataset mereka langsung ke grid, dan itu hanya nyaman untuk memiliki format SQL Server sisi server daripada format pada klien.

Query seperti yang ditunjukkan di atas sangat rapuh karena mereka memadatkan layer data dengan layer UI. Selain itu, gaya pemrograman ini secara menyeluruh mencegah prosedur tersimpan tidak dapat digunakan kembali.

Juliet
sumber
10
Pola poster-anak yang baik untuk kopling maksimum pada jumlah lapisan / lapisan abstraksi terbesar.
dkretz
3
Ini mungkin tidak baik untuk de-coupling, meskipun untuk alasan kinerja saya sering melakukan hal-hal seperti itu, perubahan berulang yang dilakukan oleh SQL Server lebih cepat daripada yang dilakukan oleh kode di mid-tier. Saya tidak mendapatkan poin reusability - tidak ada yang menghentikan Anda dari menjalankan SP dan mengganti nama cols jika diinginkan.
Joe Pineda
54
Favorit saya adalah ketika orang menyematkan HTML DAN javascript, misalnya SELECT '<a href=... onclick="">' + name '</a>'
Matt Rogish
15
Dengan kueri seperti ini, Anda dapat mengedit kisi di situs web dengan pernyataan perubahan sederhana. Atau mengubah konten ekspor, atau memformat ulang tanggal dalam laporan. Ini membuat klien senang, dan menghemat waktu saya. Jadi terima kasih, tapi tidak, terima kasih, saya akan tetap dengan pertanyaan seperti ini.
Andomar
4
@ Mat Rogish - yesus, seseorang benar-benar melakukan itu?
Axarydax
118

Inilah 3 teratas saya.

Nomor 1. Gagal menentukan daftar bidang. (Sunting: untuk mencegah kebingungan: ini adalah aturan kode produksi. Ini tidak berlaku untuk skrip analisis satu kali - kecuali saya penulisnya.)

SELECT *
Insert Into blah SELECT *

seharusnya

SELECT fieldlist
Insert Into blah (fieldlist) SELECT fieldlist

Nomor 2. Menggunakan kursor dan loop sementara, ketika loop sementara dengan variabel loop akan dilakukan.

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

Nomor 3. DateLogic melalui tipe string.

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

Seharusnya

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

Saya telah melihat lonjakan baru-baru ini "Satu permintaan lebih baik dari dua, oke?"

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

Permintaan ini membutuhkan dua atau tiga rencana eksekusi yang berbeda tergantung pada nilai parameter. Hanya satu paket eksekusi yang dihasilkan dan dimasukkan ke cache untuk teks sql ini. Paket itu akan digunakan terlepas dari nilai parameter. Ini berakibat pada kinerja buruk yang terputus-putus. Jauh lebih baik untuk menulis dua kueri (satu permintaan per rencana eksekusi yang dimaksudkan).

David B
sumber
7
hmmm, saya akan memberi Anda +1 untuk poin 2 dan 3 saja, tetapi pengembang melebih-lebihkan aturan 1. Terkadang hal itu terjadi.
annakata
1
Apa alasan di balik # 1?
jalf
29
Saat Anda menggunakan pilih *, Anda mendapatkan apa pun yang ada di tabel. Kolom-kolom itu dapat mengubah nama dan urutan. Kode klien sering bergantung pada nama dan pesanan. Setiap 6 bulan saya ditanya bagaimana cara mempertahankan pesanan kolom saat memodifikasi tabel. Jika aturan itu diikuti, itu tidak masalah.
Amy B
Saya telah menggunakan # 2 kadang-kadang, orang lain saya telah pergi rute kursor (meskipun kemudian saya pertama kali menyimpan hasil query pada tabel var, buka kursor pada itu). Saya selalu bertanya-tanya apakah seseorang telah melakukan tes kinerja keduanya.
Joe Pineda
4
... tapi tentu saja kursor hampir selalu menjadi pilihan terakhir, setelah gagal mengetahui bagaimana melakukan pekerjaan dengan set-based SQL. Saya pernah menghabiskan sekitar 45 menit dengan hati-hati membedah kursor PL / SQL raksasa yang mengerikan dalam prosedur tersimpan (menggambar diagram dari benda busuk), yang mengisi tabel temp besar kemudian memilih isi tabel temp kembali ke pemanggil untuk membuat melaporkan. Butuh 8,5 menit untuk berjalan, dengan perangkat keras yang besar. Setelah memetakan semuanya, saya bisa menggantinya dengan satu permintaan yang mengembalikan hasil yang sama dalam waktu kurang dari 2 detik. Kursor, kawan ...
Craig
71
  • Bidang kata sandi yang dapat dibaca manusia , egad. Cukup jelas.

  • Menggunakan LIKE terhadap kolom yang diindeks , dan saya hampir tergoda untuk mengatakan LIKE secara umum.

  • Daur ulang nilai-nilai PK yang dihasilkan SQL.

  • Tidak ada yang mengejutkan menyebutkan meja dewa . Tidak ada yang mengatakan "organik" seperti 100 kolom bendera bit, string besar dan bilangan bulat.

  • Lalu ada pola "I miss .ini file" : menyimpan CSV, string yang dibatasi pipa, atau data parse lain yang diperlukan dalam bidang teks besar.

  • Dan untuk MS SQL server penggunaan kursor sama sekali . Ada cara yang lebih baik untuk melakukan tugas kursor apa pun.

Diedit karena ada begitu banyak!

annakata
sumber
19
salah tentang kursor, saya akan ragu untuk mengatakan melakukan hal tertentu adalah 100% benar atau 100% salah
Shawn
4
Sejauh ini setiap contoh pertahanan kursor yang saya lihat menggunakan alat yang salah untuk pekerjaan itu. Tetapi jika semua yang Anda tahu adalah SQL, Anda menggunakannya secara tidak tepat, atau Anda belajar menulis perangkat lunak jenis lain.
dkretz
3
@tuinstoel: Bagaimana LIKE '% blah%' bisa menggunakan indeks? Pengindeksan bergantung pada pemesanan dan contoh ini mencari posisi tengah string yang acak. (Indeks diurutkan oleh karakter 1 1, dan dengan demikian melihat ke tengah 4 karakter memberikan urutan yang hampir acak ...)
MatBailie
12
Pada sebagian besar server basis data (setidaknya yang saya gunakan), LIKE dapat menggunakan indeks .. selama ini merupakan pencarian awalan (LIKE 'xxx%') - yaitu, selama karakter wildcard tidak datang dulu dalam string pencarian. Saya pikir Anda mungkin berbicara sedikit di sini.
Cowan
10
Sepertinya kamu tidak suka LIKE '%LIKE'.
Johan
62

Tidak harus menggali lebih dalam untuk itu: Tidak menggunakan pernyataan yang disiapkan.

Stesch
sumber
3
Ya. Diikuti erat dalam konteks yang sama, dalam pengalaman saya, dengan "tidak menjebak kesalahan".
dkretz
1
@stesch: Ini tidak seberapa dibandingkan dengan menggunakan tampilan dan memiliki tanggal pelaporan variabel. Tampilan adalah antipattern jika Anda memiliki tanggal pelaporan variabel (saya menganggap sebagian besar aplikasi memiliki). Akan menambahkan ini dalam jawaban yang terpisah, tetapi sayangnya sudah ditutup.
Stefan Steiger
56

Menggunakan alias tabel yang tidak berarti:

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

Membuat membaca pernyataan SQL besar jauh lebih sulit daripada yang seharusnya

Tony Andrews
sumber
49
alias? sih saya sudah melihat nama kolom yang sebenarnya seperti itu
annakata
10
alias singkat adalah OKE. Jika Anda ingin nama yang bermakna maka jangan gunakan alias sama sekali.
Joel Coehoorn
43
Dia tidak mengatakan "singkat," katanya "tidak berarti." Dalam buku saya, tidak ada yang salah dengan menggunakan e, d, dan j sebagai alias dalam kueri contoh.
Robert Rossney
11
Tentu saja, Robert - e, d, dan j akan baik-baik saja dengan saya.
Tony Andrews
8
Saya akan menggunakan emp untuk karyawan, dep untuk departemen dan pekerjaan untuk pekerjaan (atau mungkin jb) :)
Andrei Rînea
53
var query = "select COUNT(*) from Users where UserName = '" 
            + tbUser.Text 
            + "' and Password = '" 
            + tbPassword.Text +"'";
  1. Masukan pengguna secara buta mempercayai
  2. Tidak menggunakan kueri parameterisasi
  3. Kata sandi bersih
Akan
sumber
Semua yang bermanfaat dapat ditangani dengan menggunakan abstrak database pada beberapa jenis (apa saja).
dkretz
@doofledorfer: Setuju, tingkat menengah pasti akan lebih baik dalam kasus seperti ini, ditambah memberikan hasil caching sebagai efek samping yang bagus.
Joe Pineda
Contoh yang luar biasa. Jika dev mempelajari cara menggantinya dengan solusi yang baik, mereka setengah jalan untuk menjadi dev SQL yang layak.
Steve McLeod
46

Bugbears saya adalah tabel Akses kolom 450 yang telah disatukan oleh putra berusia 8 tahun dari sahabat anjing groomer Direktur Pelaksana dan tabel pencarian cerdik yang hanya ada karena seseorang tidak tahu bagaimana menormalkan struktur data dengan benar.

Biasanya, tabel pencarian ini terlihat seperti ini:

ID INT,
Nama NVARCHAR (132),
IntValue1 INT,
IntValue2 INT,
CharValue1 NVARCHAR (255),
CharValue2 NVARCHAR (255),
Date1 DATETIME,
Date2 DATETIME

Saya telah kehilangan hitungan jumlah klien yang pernah saya lihat yang memiliki sistem yang mengandalkan kekejian seperti ini.

Pete OHanlon
sumber
1
Lebih buruk lagi, saya membaca bahwa dalam versi terbaru dari Access yang sebenarnya didukung secara otomatis, yang saya khawatirkan akan mendorong lebih banyak Value1, Value2, Value3 ini ... fetichism kolom
Joe Pineda
Tunggu - jadi putra berusia 8 tahun itu adalah putra dari groomer anjing?
barrypicker
28

Yang paling saya sukai adalah

  1. Menggunakan spasi saat membuat tabel, sprocs dll. Saya baik-baik saja dengan CamelCase atau under_scores dan tunggal atau bentuk jamak dan huruf besar atau huruf kecil tetapi harus merujuk ke tabel atau kolom [dengan spasi], terutama jika [spasi aneh] (ya, Saya mengalami ini) benar-benar membuat saya jengkel.

  2. Data yang dinormalisasi. Sebuah tabel tidak harus dinormalisasi secara sempurna, tetapi ketika saya bertemu dengan tabel karyawan yang memiliki informasi tentang skor evaluasi mereka saat ini atau apa pun yang utama, itu memberi tahu saya bahwa saya mungkin perlu membuat tabel terpisah di beberapa titik dan kemudian coba sinkronkan. Saya akan menormalkan data terlebih dahulu dan kemudian jika saya melihat tempat di mana denasionalisasi membantu, saya akan mempertimbangkannya.

  3. Terlalu sering menggunakan pandangan atau kursor. Tampilan memiliki tujuan, tetapi ketika setiap tabel dibungkus dalam tampilan itu terlalu banyak. Saya harus menggunakan kursor beberapa kali, tetapi secara umum Anda dapat menggunakan mekanisme lain untuk ini.

  4. Mengakses. Bisakah suatu program menjadi anti-pola? Kami memiliki SQL Server di tempat kerja saya, tetapi sejumlah orang menggunakan akses karena ketersediaannya, "kemudahan penggunaan" dan "keramahan" untuk pengguna non-teknis. Ada terlalu banyak di sini untuk dituju, tetapi jika Anda berada di lingkungan yang sama, Anda tahu.

Jamal Hansen
sumber
2
# 4 - ada utas lain hanya untuk <a href=' stackoverflow.com/questions/327199/…> :).
dkretz
4
Akses BUKAN DBMS. Ini adalah lingkungan RAD, termasuk manajer basis data yang sangat sederhana. SQL Server, Oracle, dkk. tidak akan pernah menggantikannya, kecuali jika Anda menambahkan bahasa seperti VB dan fasilitas seperti Crystal Reports.
Joe Pineda
26

gunakan SP sebagai awalan dari nama prosedur toko karena ia akan mencari lebih dulu di lokasi prosedur sistem daripada yang kustom.

Oscar Cabrero
sumber
1
Dapat juga diperluas untuk menggunakan awalan umum lainnya untuk semua prosedur tersimpan, membuatnya lebih sulit untuk memilih daftar yang diurutkan.
dkretz
7
+1 untuk komentar doofledorfer !! Saya sudah sering melihat ini, saya menemukan ini bodoh dan memang membuat mencari SP tertentu sangat sulit !!! Juga diperluas ke "vw_" untuk tampilan, "tbl_" untuk tabel dan sejenisnya, betapa aku benci mereka!
Joe Pineda
1
Awalan dapat berguna jika Anda membuat skrip objek ke file (misalnya: untuk kontrol sumber, penyebaran atau migrasi)
Rick
1
Kenapa bisa berguna untuk awalan setiap prosedur tersimpan tunggal dengan sp atau usp? Itu hanya membuat lebih sulit untuk memindai daftar untuk yang Anda inginkan.
Ryan Lundy
25

Terlalu sering menggunakan meja sementara dan kursor.

Rockcoder
sumber
2
Bukti bagus bahwa "yang saya tahu adalah bahasa prosedural".
dkretz
2
Terlalu sering menggunakan sesuatu secara definisi tidak diinginkan. Contoh spesifik di mana menggunakan tabel temp / kursor tidak diperlukan akan sangat membantu.
Jace Rhea
6
Sebagian besar saya melihat tabel temp kurang digunakan. dengan SQL Server sering Anda mendapatkan keuntungan kinerja dengan melakukan hal-hal dengan sekelompok tabel temp bukannya satu permintaan monolitik.
Cervo
24

Untuk menyimpan nilai waktu, hanya zona waktu UTC yang harus digunakan. Waktu setempat tidak boleh digunakan.

Frank Schwieterman
sumber
3
Saya masih belum menemukan solusi sederhana yang baik untuk mengkonversi dari UTC ke waktu lokal untuk tanggal di masa lalu, ketika penghematan siang hari harus dipertimbangkan, dengan tanggal perubahan yang berbeda di seluruh tahun dan negara, serta semua pengecualian di dalam negara. Jadi UTC tidak menyelamatkan Anda dari kompleksitas konversi. Namun, penting untuk memiliki cara untuk mengetahui zona waktu dari setiap datetime yang disimpan.
ckarras
1
@CsongorHalmai Banyak tempat mempraktikkan penghematan siang hari, sehingga nilai waktu dalam satu jam dari waktu dapat menjadi ambigu.
Frank Schwieterman
Itu tentu saja tepat untuk masa kini dan masa lalu, tetapi untuk masa depan, terutama masa depan yang cukup jauh, zona waktu eksplisit seringkali menjadi kebutuhan. Jika Anda memiliki opsi 30 tahun yang baru saja ditulis dan kedaluwarsa pada 2049-09-27T17: 00: 00 waktu New York, maka Anda tidak bisa begitu saja berasumsi bahwa itu akan menjadi 21: 00: 00Z. Kongres AS mungkin akan mengubah aturan DST. Anda harus memisahkan waktu lokal dan zona waktu sebenarnya (Amerika / New_York).
John Cowan
23

menggunakan @@ IDENTITY alih-alih SCOPE_IDENTITY ()

Dikutip dari jawaban ini :

  • @@ IDENTITY mengembalikan nilai identitas terakhir yang dihasilkan untuk tabel apa pun di sesi saat ini, di semua ruang lingkup. Anda harus berhati-hati di sini, karena melintasi batas. Anda bisa mendapatkan nilai dari pemicu, alih-alih pernyataan Anda saat ini.
  • SCOPE_IDENTITY mengembalikan nilai identitas terakhir yang dihasilkan untuk tabel apa pun di sesi saat ini dan ruang lingkup saat ini. Umumnya apa yang ingin Anda gunakan.
  • IDENT_CURRENT mengembalikan nilai identitas terakhir yang dihasilkan untuk tabel tertentu dalam sesi apa pun dan ruang lingkup apa pun. Ini memungkinkan Anda menentukan tabel yang Anda inginkan nilainya, jika kedua di atas tidak cukup apa yang Anda butuhkan (sangat jarang). Anda bisa menggunakan ini jika Anda ingin mendapatkan nilai IDENTITAS saat ini untuk tabel yang Anda belum memasukkan catatan.
Brann
sumber
+1 sangat benar, dapat menyebabkan bug yang sulit disingkirkan
Axarydax
23

Menggunakan kembali bidang 'mati' untuk sesuatu yang tidak dimaksudkan (misalnya menyimpan data pengguna dalam bidang 'Faks') - sangat menggoda sebagai perbaikan cepat!

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

dan dengan asumsi bahwa hasilnya akan diurutkan berdasarkan some_column. Saya telah melihat ini sedikit dengan Sybase di mana asumsi itu berlaku (untuk saat ini).

Adrian Pronk
sumber
1
upvote untuk EVER dengan asumsi urutan sortir, hanya karena begitulah cara itu muncul di alat kueri itu suatu waktu
Joel Coehoorn
3
Saya bahkan melihat ini dilaporkan sebagai bug lebih dari sekali.
dkretz
6
di MySQL, ini didokumentasikan untuk mengurutkan. < dev.mysql.com/doc/refman/5.0/id/select.html >. Jadi salahkan MySQL (lagi).
derobert
1
Di Oracle, hasil yang tidak disortir (hampir) selalu cocok dengan pengelompokan - hingga versi 10G. Banyak pengerjaan ulang untuk para pengembang yang dulu meninggalkan ORDER BY!
Tony Andrews
1
Saya bahkan berada di kelas pelatihan di mana ini dinyatakan sebagai fakta untuk SQL Server. Saya harus protes sangat keras. Untuk hanya menyimpan untuk mengetik 20 karakter, Anda mengandalkan perilaku yang tidak jelas atau tidak terdokumentasi.
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

Atau, menjejalkan semuanya menjadi satu baris.

Radu
sumber
Menggunakan kueri komentar sebelumnya, hanya karena itu adalah pernyataan SQL pertama yang saya miliki.
Jasper Bekkers
17
  • The FROM TableA, TableB WHEREsintaks untuk BERGABUNG daripadaFROM TableA INNER JOIN TableB ON

  • Membuat asumsi bahwa permintaan akan dikembalikan disortir dengan cara tertentu tanpa memasukkan klausa ORDER BY, hanya karena itulah yang muncul selama pengujian di alat kueri.

Joel Coehoorn
sumber
5
Oracle DBAs saya selalu mengeluh bahwa saya menggunakan "ANSI joins", yaitu apa yang Anda sajikan sebagai cara yang benar. Tetapi saya terus melakukannya, dan saya curiga bahwa jauh di lubuk hati mereka lebih tahu.
Steve McLeod
1
Saya menduga bahwa Oracle berharap standar SQL akan hilang. :-) Selain itu, Anda tidak dapat menggabungkan GABUNGAN implisit dan eksplisit (alias Gabung ANSI) di MySQL 5 - tidak berfungsi. Yang merupakan argumen lain untuk JIONs eksplisit.
statika
3
Saya akan mengatakan bahwa A INNER JOIN B ON adalah pola anti. Saya lebih suka A INNER JOIN B MENGGUNAKAN.
John Nilsson
Oracle mendukung sintaksis ANSI sekarang, tetapi mereka dulu memiliki sintaks yang sangat aneh untuk sambungan luar di masa lalu dan ada terlalu banyak orang yang masih menggunakannya.
Cervo
baik ... Oracle masih tidak akan membiarkan Anda menggunakan ANSI bergabung untuk Fast Refreshable, On-Commit Views
Terwujud
14

Belajar SQL dalam enam bulan pertama karir mereka dan tidak pernah belajar hal lain selama 10 tahun ke depan. Khususnya tidak belajar atau secara efektif menggunakan fitur windowing / analitik SQL. Khususnya penggunaan over () dan partisi oleh.

Fungsi jendela, seperti fungsi agregat, melakukan agregasi pada kumpulan baris yang ditentukan (grup), tetapi alih-alih mengembalikan satu nilai per grup, fungsi jendela dapat mengembalikan beberapa nilai untuk setiap grup.

Lihat O'Reilly SQL Cookbook Lampiran A untuk tinjauan umum yang bagus dari fungsi windowing.

Brian
sumber
12

Saya perlu menempatkan favorit saya saat ini di sini, hanya untuk membuat daftar lengkap. Antipattern favorit saya tidak menguji kueri Anda .

Ini berlaku ketika:

  1. Kueri Anda melibatkan lebih dari satu tabel.
  2. Anda pikir Anda memiliki desain yang optimal untuk kueri, tetapi jangan repot-repot menguji asumsi Anda.
  3. Anda menerima kueri pertama yang berfungsi, tanpa petunjuk apakah itu hampir dioptimalkan.

Dan setiap tes dijalankan terhadap data atipikal atau tidak mencukupi tidak masuk hitungan. Jika ini adalah prosedur yang tersimpan, masukkan pernyataan tes ke dalam komentar dan simpan, dengan hasilnya. Kalau tidak, masukkan ke dalam komentar dengan kode hasilnya.

le dorfier
sumber
Teknik yang sangat berguna untuk uji T-SQL minimal: Dalam file .SQL tempat Anda mendefinisikan SP, UDF, dll., Segera setelah itu buat tes blok seperti IF 1 = 2 BEGIN (contoh kasus untuk kode Anda, dengan hasil yang diharapkan sebagai komentar) AKHIR
Joe Pineda
SQL Server mem-parsing kode di dalam blok tes, meskipun tidak pernah dieksekusi. Jadi, ketika objek Anda diubah dan menerima lebih banyak parameter, atau dari jenis yang berbeda, dll. Atau objek yang bergantung padanya dimodifikasi, Anda akan menerima kesalahan hanya dengan meminta rencana eksekusi!
Joe Pineda
Tidak selalu mungkin untuk menguji dengan data nyata. Seringkali server dev / server "test" dibayar rendah dan mendapat sebagian kecil dari server langsung. Umumnya tes tidak disukai terhadap server hidup. Beberapa tempat lebih baik dan memiliki server uji atau pementasan dengan data langsung.
Cervo
11

Penyalahgunaan Tabel Sementara.

Khususnya hal semacam ini:

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)

Jangan membangun tabel sementara dari kueri, hanya untuk menghapus baris yang tidak Anda butuhkan.

Dan ya, saya telah melihat halaman kode dalam bentuk ini di DB produksi.

geofftnz
sumber
1
+1, saya setuju. Meskipun, saya telah menemukan setidaknya satu atau dua kasus di mana teknik ini telah meningkatkan kinerja - pertanyaan yang terlibat rumit untuk sedikitnya.
aēr
1
Benar - mereka punya tempat, hanya saja tidak di setiap permintaan :)
geofftnz
1
Terkadang Anda harus melakukan itu jika kondisinya sangat rumit. Benar itu bisa disalahgunakan secara ekstrem. Tetapi berkali-kali penghapusan sederhana jauh lebih sederhana daripada logika untuk mendapatkan kasus dalam permintaan awal. Kadang-kadang juga jika klausa ini tidak diisi ulang permintaan awal akan melambat. Tetapi hanya melakukannya pada tabel temp yang lebih kecil lebih efisien. Dan lain kali Anda terus menambahkan kasus yang terus ditambahkan oleh pebisnis setelah fakta.
Cervo
9

Pandangan pelawan: obsesi berlebihan dengan normalisasi.

Sebagian besar sistem SQL / RBDBs memberikan satu banyak fitur (transaksi, replikasi) yang cukup berguna, bahkan dengan data yang tidak diformalkan. Ruang disk murah, dan kadang-kadang bisa lebih sederhana (kode lebih mudah, waktu pengembangan lebih cepat) untuk memanipulasi / memfilter / mencari data yang diambil, daripada menulis skema 1NF, dan menangani semua kerepotan di dalamnya (gabungan yang kompleks, sub-pilihan yang tidak menyenangkan) , dll).

Saya telah menemukan bahwa sistem yang terlalu dinormalisasi seringkali merupakan optimasi prematur, terutama pada tahap pengembangan awal.

(lebih banyak pemikiran tentang itu ... http://writeonly.wordpress.com/2008/12/05/simple-object-db-using-json-and-python-sqlite/ )

Gregg Lind
sumber
22
Saya pikir non-normalisasi sering optimasi prematur.
tuinstoel
Terkadang, terkadang tidak. Untungnya, seringkali mudah untuk menguji, dan opsi yang berbeda berfungsi dengan kebutuhan db yang berbeda.
Gregg Lind
17
Normalisasi bukan hanya untuk penghematan ruang disk. Itu juga untuk membuat sumber otoritatif untuk data. Jika data disimpan hanya satu tempat, maka konsistensi bukanlah produk sampingan dari pengkodean yang cermat, tetapi sebaliknya merupakan produk sampingan dari desain.
Grant Johnson
Menyimpan data majemuk dalam format JSON adalah satu hal: ada lebih banyak dan lebih banyak dukungan untuk itu, dan itu merupakan tradeoff yang disadari. Menggunakan nilai-nilai yang dipisahkan dengan koma (atau apa pun) dalam upaya untuk menyelamatkan satu join adalah sen dolar dan bodoh.
John Cowan
solusi noSQL menunjukkan manfaat kinerja dengan mengorbankan data duplikat dengan menghilangkan pencarian multi-tabel. Menempatkan seluruh hal normalisasi di kepalanya. Dalam beberapa contoh, data dikumpulkan di banyak tempat untuk memastikan satu proses memiliki waktu respons tercepat. Tentu saja, pertanyaan tentang sumber-sumber yang berwibawa ikut bermain.
barrypicker
9

Saya hanya menyatukan ini, berdasarkan pada beberapa respons SQL di sini pada SO.

Ini adalah antipattern yang serius untuk berpikir bahwa pemicu adalah untuk database seperti event handler ke OOP. Ada persepsi bahwa sembarang logika lama dapat dimasukkan ke dalam pemicu, untuk dipecat ketika transaksi (peristiwa) terjadi di atas meja.

Tidak benar. Salah satu perbedaan besar adalah bahwa pemicu sinkron - dengan balas dendam, karena mereka sinkron pada operasi yang ditetapkan, bukan pada operasi baris. Di sisi OOP, justru sebaliknya - peristiwa adalah cara yang efisien untuk menerapkan transaksi asinkron.

dkretz
sumber
8

Prosedur atau Fungsi Tersimpan tanpa komentar ...

Bliek
sumber
Dan views;) Functions true, kecuali fungsi bernilai tabel (= views with parameter).
Stefan Steiger
7

1) Saya tidak tahu ini anti-pola "resmi", tapi saya tidak suka dan mencoba untuk menghindari string literal sebagai nilai ajaib dalam kolom database.

Contoh dari tabel 'gambar' MediaWiki:

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",

(Saya hanya melihat casing yang berbeda, hal lain yang harus dihindari)

Saya merancang kasus-kasus seperti pencarian int ke dalam tabel ImageMediaType dan ImageMajorMime dengan kunci primer int.

2) konversi tanggal / string yang bergantung pada pengaturan NLS tertentu

CONVERT(NVARCHAR, GETDATE())

tanpa pengidentifikasi format

devio
sumber
Dan juga tidak ada lekukan sintaksis. Argghh.
dkretz
2
Kenapa ini buruk? tentunya jika Anda mencoba untuk mengekspresikan serangkaian nilai ini berfungsi sama baiknya dengan tabel pencarian, dan lebih cocok dengan kode yang memanggilnya. Id lebih suka memiliki enum dalam kode aplikasi saya yang memetakan ke kendala enum di DB saya daripada enum dalam kode aplikasi saya yang memetakan ke baris tertentu dari tabel pencarian. Rasanya lebih bersih.
Jack Ryan
@JackRyan: Ini buruk karena ketika Anda mengubah daftar enum nanti, Anda harus ingat untuk mengubahnya di dua tempat sekarang. Itu melanggar KERING . Basis data harus menjadi satu-satunya sumber kebenaran.
Gerrat
7

Subquery identik dalam kueri.

EvilTeach
sumber
10
Sayangnya, kadang-kadang Anda tidak bisa menghindarinya - dalam SQL 2000 tidak ada kata kunci "DENGAN", dan menggunakan UDF untuk merangkum subkueri umum kadang-kadang mengarah pada hukuman kinerja, salahkan MS pada ...
Joe Pineda
Mudah-mudahan mereka akan menambahkan satu hari ini.
EvilTeach
Di SQL 2000, Anda bisa menggunakan variabel tabel.
Rekursif
@recursive: Anda tidak dapat memiliki indeks pada variabel tabel, yang sering membuatnya lebih lambat daripada subquery. Namun Anda bisa menggunakan tabel sementara dengan indeks khusus.
Rick
Keren, telah bekerja dengan SQL selama bertahun-tahun, dan bahkan tidak tahu Common Table Expressions ada (meskipun saya akan membutuhkannya). Sekarang saya lakukan! Terima kasih!
sleske
7
  • Tampilan yang Diubah - Tampilan yang terlalu sering diubah dan tanpa pemberitahuan atau alasan. Perubahan akan diketahui pada waktu yang paling tidak tepat atau lebih buruk salah dan tidak pernah diperhatikan. Mungkin aplikasi Anda akan rusak karena seseorang memikirkan nama yang lebih baik untuk kolom itu. Sebagai aturan, pandangan harus memperluas kegunaan tabel dasar sambil mempertahankan kontrak dengan konsumen. Perbaiki masalah tetapi jangan menambahkan fitur atau mengubah perilaku yang lebih buruk, untuk itu buat tampilan baru. Untuk mengurangi jangan berbagi pandangan dengan proyek lain dan, gunakan CTE ketika platform memungkinkan. Jika toko Anda memiliki DBA, Anda mungkin tidak dapat mengubah tampilan tetapi semua tampilan Anda akan usang dan atau tidak berguna dalam hal ini.

  • The! Paramed - Dapatkan kueri memiliki lebih dari satu tujuan? Mungkin tetapi orang berikutnya yang membacanya tidak akan tahu sampai meditasi mendalam. Bahkan jika Anda tidak membutuhkannya sekarang kemungkinan Anda akan, bahkan jika itu "hanya" untuk debug. Menambahkan parameter menurunkan waktu perawatan dan menjaga keadaan tetap KERING. Jika Anda memiliki klausa di mana Anda harus memiliki parameter.

  • Kasing tanpa KASUS -

    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  
jason saldo
sumber
Mencintai yang ketiga. Saya sudah menggunakannya secara lokal ...
alphadogg
Terima kasih untuk alat peraga. :)
jason saldo
5

Dua yang paling saya temukan, dan dapat memiliki biaya yang signifikan dalam hal kinerja adalah:

  • Menggunakan kursor alih-alih ekspresi berbasis set. Saya kira ini sering terjadi ketika programmer berpikir secara prosedural.

  • Menggunakan sub-kueri terkait, saat bergabung ke tabel turunan dapat melakukan pekerjaan.

Mitch Wheat
sumber
Saya setuju jika Anda mengatakan apa yang saya pikir Anda maksud; meskipun sub-kueri berkorelasi adalah jenis tabel diturunkan IIRC.
dkretz
1
Tabel turunan adalah operasi himpunan, sedangkan subquery berkorelasi berjalan untuk setiap baris dalam kueri luar, membuatnya kurang efisien (9 kali dari 10)
Mitch Wheat
Beberapa tahun yang lalu saya terkejut bahwa SQL S. entah bagaimana dioptimalkan untuk menangani kueri berkorelasi: untuk yang sederhana Anda mendapatkan rencana eksekusi yang sama seperti dengan kueri yang setara secara logis menggunakan GABUNG! Juga, pertanyaan berkorelasi yang membuat Oracle hanya bisa berjalan lambat di SQL S.!
Joe Pineda
Itu sebabnya saya selalu mengujinya dua arah. Dan saya <i> lakukan </i> biasanya mencoba keduanya. Dalam prakteknya, untuk SQL Server, saya biasanya menemukan sq berkorelasi menjadi tidak lebih lambat.
dkretz
3
TOLONG pahami bahwa subquery yang berkorelasi dan gabungan adalah IDENTIK (dalam kebanyakan kasus). Mereka bahkan bukan hal-hal yang berbeda yang dioptimalkan satu sama lain, tetapi hanya representasi tekstual yang berbeda dari operasi yang sama.
erikkallen
5

Menempatkan barang di tabel sementara, terutama orang yang beralih dari SQL Server ke Oracle memiliki kebiasaan menggunakan tabel sementara secara berlebihan. Cukup gunakan pernyataan pilih bersarang.

tuinstoel
sumber
5

Pengembang yang menulis kueri tanpa memiliki ide bagus tentang apa yang membuat aplikasi SQL (baik permintaan individu dan sistem multi-pengguna) cepat atau lambat. Ini termasuk ketidaktahuan tentang:

  • strategi minimisasi fisik I / O, mengingat bahwa hambatan yang paling banyak adalah I / O bukan CPU
  • Dampak perf dari berbagai jenis akses penyimpanan fisik (mis. banyak I / O berurutan akan lebih cepat daripada banyak I / O acak kecil, meskipun lebih sedikit jika penyimpanan fisik Anda adalah SSD!)
  • cara menyetel kueri jika DBMS menghasilkan rencana kueri yang buruk
  • cara mendiagnosis kinerja basis data yang buruk, cara "men-debug" kueri lambat, dan cara membaca rencana kueri (atau MENJELASKAN, tergantung pada DBMS pilihan Anda)
  • mengunci strategi untuk mengoptimalkan throughput dan menghindari kebuntuan dalam aplikasi multi-pengguna
  • pentingnya batching dan trik lain untuk menangani pemrosesan set data
  • desain tabel dan indeks untuk menyeimbangkan ruang dan kinerja terbaik (mis. mencakup indeks, menjaga indeks sedapat mungkin, mengurangi tipe data hingga ukuran minimum yang diperlukan, dll.)
Justin Grant
sumber
3

Menggunakan SQL sebagai paket ISAM (Indexed Sequential Access Method) yang dimuliakan. Secara khusus, kursor bersarang alih-alih menggabungkan pernyataan SQL menjadi pernyataan tunggal, meskipun lebih besar. Ini juga dianggap sebagai 'penyalahgunaan pengoptimal' karena sebenarnya tidak banyak yang dapat dilakukan pengoptimal. Ini dapat dikombinasikan dengan pernyataan yang tidak disiapkan untuk inefisiensi maksimum:

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

Solusi yang benar (hampir selalu) adalah menggabungkan dua pernyataan SELECT menjadi satu:

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

Satu-satunya keuntungan untuk versi loop ganda adalah bahwa Anda dapat dengan mudah melihat jeda antara nilai-nilai dalam Table1 karena loop dalam berakhir. Ini bisa menjadi faktor dalam laporan break-control.

Selain itu, pengurutan dalam aplikasi biasanya tidak boleh.

Jonathan Leffler
sumber
Gaya, meskipun bukan sintaks ini, sangat merajalela dalam PHP dalam pengalaman saya.
dkretz
Sintaks sebenarnya adalah IBM Informix-4GL - tetapi cukup jelas untuk tidak membutuhkan banyak cara penjelasan (saya pikir). Dan gaya ini merajalela di banyak program SQL - terlepas dari bahasa pemrograman.
Jonathan Leffler
Kecuali fakta bahwa Anda menggunakan antipattern yang terkenal (implisit bergabung) untuk menggambarkan antipattern Anda, semacam mengalahkan intinya.
Johan
Dan tentu saja penggunaan kursor sama sekali adalah antipattern SQl. Hampir semua kursor dapat ditulis ulang sebagai operasi berbasis set. Beberapa yang tidak bisa adalah jenis yang hanya ditulis oleh DBA dengan pengalaman bertahun-tahun dan yang mengerti bagaimana seharusnya internal database bekerja. Tidak ada aplikasi dev yang perlu menulis kursor SQL.
HLGEM
3

Menggunakan kunci utama sebagai pengganti untuk alamat rekaman dan menggunakan kunci asing sebagai pengganti untuk pointer yang tertanam dalam catatan.

Walter Mitty
sumber