Kemarin saya berdiskusi dengan programmer "hobi" (saya sendiri adalah programmer profesional). Kami menemukan beberapa karyanya, dan dia berkata dia selalu menanyakan semua kolom dalam database-nya (bahkan pada / di server produksi / kode).
Saya mencoba meyakinkan dia untuk tidak melakukannya, tetapi belum begitu berhasil. Menurut pendapat saya seorang programmer hanya harus menanyakan apa yang sebenarnya dibutuhkan demi "kecantikan", efisiensi dan lalu lintas. Apakah saya salah dengan pandangan saya?
Jawaban:
Pikirkan tentang apa yang Anda dapatkan kembali, dan bagaimana Anda mengikat mereka ke variabel dalam kode Anda.
Sekarang pikirkan apa yang terjadi ketika seseorang memperbarui skema tabel untuk menambahkan (atau menghapus) kolom, bahkan yang tidak Anda gunakan secara langsung.
Menggunakan pilih * saat Anda mengetik kueri dengan tangan baik-baik saja, bukan saat Anda menulis kueri untuk kode.
sumber
Perubahan Skema
foo
, dan tabel lain dalam kueri menambahkan kolomfoo
, cara ini ditangani dapat menyebabkan masalah ketika mencoba untuk mendapatkan kolom yang tepatfoo
.Either way, perubahan skema dapat menyebabkan masalah dengan ekstraksi data.
Lebih lanjut pertimbangkan jika kolom yang sedang digunakan dihapus dari tabel. The
select * from ...
masih bekerja tapi kesalahan ketika mencoba untuk menarik data dari hasil set. Jika kolom ditentukan dalam kueri, kueri akan keluar sebagai gantinya memberikan indikasi yang jelas tentang apa dan di mana masalahnya.Overhead data
Beberapa kolom dapat memiliki sejumlah besar data yang terkait dengannya. Memilih kembali
*
akan menarik semua data. Yap, ini adavarchar(4096)
pada 1000 baris yang telah Anda pilih untuk kembali memberi Anda kemungkinan tambahan 4 megabita data yang tidak Anda perlukan, tetapi dikirim melalui kabel.Terkait dengan perubahan skema, varchar itu mungkin tidak ada di sana ketika Anda pertama kali membuat tabel, tetapi sekarang ada di sana.
Gagal menyampaikan maksud
Ketika Anda memilih kembali
*
dan mendapatkan 20 kolom tetapi hanya membutuhkan 2 kolom, Anda tidak menyampaikan maksud kode. Ketika melihat permintaan yang dilakukanselect *
seseorang tidak tahu apa bagian penting dari itu. Bisakah saya mengubah kueri untuk menggunakan paket lain ini untuk membuatnya lebih cepat dengan tidak menyertakan kolom ini? Saya tidak tahu karena maksud dari pengembalian kueri tidak jelas.Mari kita lihat beberapa biola SQL yang mengeksplorasi perubahan skema sedikit lebih.
Pertama, basis data awal: http://sqlfiddle.com/#!2/a67dd/1
DDL:
SQL:
Dan kolom Anda kembali adalah
oneid=1
,data=42
,twoid=2
, danother=43
.Sekarang, apa yang terjadi jika saya menambahkan kolom ke tabel satu? http://sqlfiddle.com/#!2/cd0b0/1
Dan hasil saya dari query yang sama seperti sebelumnya yang
oneid=1
,data=42
,twoid=2
, danother=foo
.Perubahan pada salah satu tabel mengganggu nilai-nilai a
select *
dan tiba-tiba pengikatan 'lain' ke int akan menimbulkan kesalahan dan Anda tidak tahu mengapa.Jika bukan pernyataan SQL Anda
Perubahan ke tabel satu tidak akan mengganggu data Anda. Kueri itu menjalankan hal yang sama sebelum perubahan dan setelah perubahan.
Pengindeksan
Ketika Anda melakukan,
select * from
Anda menarik semua baris dari semua tabel yang sesuai dengan kondisi. Bahkan meja Anda benar-benar tidak peduli. Meskipun ini berarti lebih banyak data yang ditransfer, ada masalah kinerja lain yang mengintai di stack.Indeks. (terkait pada SO: Bagaimana cara menggunakan indeks dalam pernyataan pilih? )
Jika Anda menarik kembali banyak kolom, pengoptimal rencana basis data dapat mengabaikan menggunakan indeks karena Anda masih perlu mengambil semua kolom itu dan akan membutuhkan lebih banyak waktu untuk menggunakan indeks dan kemudian mengambil semua kolom dalam kueri daripada hanya untuk melakukan scan tabel lengkap.
Jika Anda hanya memilih, katakanlah, nama belakang pengguna (yang sering Anda lakukan dan memiliki indeks), basis data dapat melakukan pemindaian indeks saja (pemindaian indeks postgres wiki saja , pemindaian tabel lengkap mysql vs penuh pemindaian indeks , Pemindaian Hanya-Indeks: Menghindari Akses Tabel ).
Ada sedikit optimisasi tentang membaca hanya dari indeks jika memungkinkan. Informasi dapat ditarik lebih cepat pada setiap halaman indeks karena Anda juga menarik lebih sedikit - Anda tidak menarik semua kolom lain untuk
select *
. Mungkin saja pemindaian hanya indeks untuk mengembalikan hasil pada urutan 100x lebih cepat (sumber: Pilih * buruk ).Ini tidak mengatakan bahwa pemindaian indeks lengkap sangat bagus, ini masih pemindaian penuh - tetapi lebih baik daripada pemindaian tabel penuh. Setelah Anda mulai mengejar semua cara yang
select *
menyakitkan kinerja Anda terus menemukan yang baru.Bacaan terkait
sumber
select *
?Kekhawatiran lain: jika itu adalah
JOIN
kueri dan Anda mengambil hasil kueri ke dalam array asosiatif (seperti yang terjadi di PHP), itu rawan bug.Masalahnya adalah itu
foo
memiliki kolomid
danname
bar
memiliki kolomid
danaddress
,SELECT * FROM foo JOIN bar ON foo.id = bar.id
tebak apa yang terjadi ketika seseorang menambahkan kolom
name
kebar
tabel.Kode tiba-tiba akan berhenti berfungsi dengan baik, karena sekarang
name
kolom muncul di hasil dua kali dan jika Anda menyimpan hasilnya ke dalam array, data dari secondname
(bar.name
) akan menimpa yang pertamaname
(foo.name
)!Ini adalah bug yang tidak menyenangkan karena sangat tidak jelas. Mungkin perlu beberapa saat untuk mencari tahu, dan tidak mungkin orang menambahkan kolom lain ke meja bisa mengantisipasi efek samping yang tidak diinginkan.
(Kisah nyata).
Jadi, jangan gunakan
*
, kendalikan kolom apa yang Anda ambil dan gunakan alias jika perlu.sumber
SELECT
klausa Anda dan ini adalah saat Anda berharap menemukan nama itu tidak unik. BTW Saya tidak berpikir itu sangat langka dalam sistem dengan database besar. Seperti yang saya katakan, saya pernah menghabiskan beberapa jam berburu bug ini dalam bola kode PHP yang besar. Dan saya menemukan kasing lain sekarang: stackoverflow.com/q/17715049/168719Meminta setiap kolom mungkin benar-benar sah, dalam banyak kasus.
Selalu meminta setiap kolom tidak.
Ini lebih berfungsi untuk mesin basis data Anda, yang harus mematikan dan mencari-cari di sekitar metadata internal untuk mencari tahu kolom mana yang perlu ditangani sebelum dapat melanjutkan bisnis nyata untuk benar-benar mendapatkan data dan mengirimkannya kembali kepada Anda. OK, ini bukan overhead terbesar di dunia, tetapi katalog sistem bisa menjadi hambatan yang cukup besar.
Ini lebih berfungsi untuk jaringan Anda, karena Anda menarik kembali sejumlah bidang ketika Anda mungkin hanya menginginkan satu atau dua bidang. Jika seseorang [lain] pergi dan menambahkan beberapa lusin bidang tambahan, yang semuanya berisi potongan teks besar, throughput Anda tiba-tiba melewati lantai - tanpa alasan yang jelas. Ini menjadi lebih buruk jika klausa "di mana" Anda tidak terlalu bagus dan Anda menarik banyak baris juga - itu berpotensi banyak data yang menginjak jalannya di jaringan kepada Anda (yaitu akan lambat).
Ini lebih berfungsi untuk aplikasi Anda, harus menarik kembali dan menyimpan semua data tambahan ini yang sangat mungkin tidak peduli.
Anda menjalankan risiko kolom mengubah urutannya. OK, Anda tidak perlu khawatir tentang ini (dan Anda tidak akan melakukannya jika Anda hanya memilih kolom yang Anda butuhkan) tetapi, jika Anda mendapatkan semuanya sekaligus dan seseorang [lain] memutuskan untuk mengatur ulang urutan kolom dalam tabel , yang dibuat dengan hati-hati, ekspor CSV yang Anda berikan ke akun di aula tiba-tiba berubah menjadi pot - lagi, tanpa alasan yang jelas.
BTW, saya sudah mengatakan "seseorang [lain]" beberapa kali, di atas. Ingat bahwa database pada dasarnya multi-pengguna; Anda mungkin tidak memiliki kendali atas mereka yang Anda pikir Anda miliki.
sumber
TOP
batasan; Saya tidak yakin seberapa penting itu jika kode dibaca sebanyak yang ingin ditampilkan dan kemudian membuang kueri. Saya pikir respons permintaan diproses agak malas, meskipun saya tidak tahu detailnya. Bagaimanapun, saya berpikir bahwa daripada mengatakannya "tidak sah", akan lebih baik untuk mengatakan "... sah dalam jumlah yang jauh lebih sedikit"; pada dasarnya, saya akan meringkas kasus-kasus yang sah sebagai kasus-kasus di mana pengguna akan memiliki ide yang lebih baik apa yang berarti daripada programmer.Jawaban singkatnya adalah: itu tergantung pada database apa yang mereka gunakan. Relasional database dioptimalkan untuk mengekstraksi data yang Anda butuhkan dalam cepat, handal dan atom cara. Pada dataset besar dan pertanyaan kompleks, ini jauh lebih cepat dan mungkin lebih aman daripada SELECTing * dan melakukan yang setara dengan gabungan di sisi 'kode'. Toko-toko kunci mungkin tidak menerapkan fungsionalitas seperti itu, atau mungkin tidak cukup matang untuk digunakan dalam produksi.
Yang mengatakan, Anda masih dapat mengisi struktur data apa pun yang Anda gunakan dengan SELECT * dan mengerjakan sisanya dalam kode tetapi Anda akan menemukan hambatan kinerja jika Anda ingin skala.
Perbandingan terdekat adalah pengurutan data: Anda dapat menggunakan quicksort atau bubblesort dan hasilnya akan benar. Tetapi tidak akan dioptimalkan, dan pasti akan memiliki masalah ketika Anda memperkenalkan konkurensi dan perlu mengurutkan secara atom.
Tentu saja, lebih murah untuk menambahkan RAM dan CPU daripada berinvestasi pada seorang programmer yang dapat melakukan query SQL dan bahkan memiliki pemahaman yang kabur tentang apa itu JOIN.
sumber
Customer customer = this._db.Customers.Where( “it.ID = @ID”, new ObjectParameter( “ID”, id ) ).First();
Lihat Time to Take Offense di halaman 2.var cmd = db.CreateCommand(); cmd.CommandText = "SELECT TOP 1 * FROM Customers WHERE ID = @ID"; cmd.Parameters.AddWithValue("@ID", id); var result = cmd.ExecuteReader();
.... dan kemudian lanjutkan untuk membuat Pelanggan dari setiap baris. LINQ mengalahkan celana itu.var customer = _db.Customers.Where(it => it.id == id).First();
.IMO, ini tentang menjadi eksplisit vs implisit. Ketika saya menulis kode, saya ingin itu berfungsi karena saya membuatnya bekerja, bukan hanya karena semua bagian kebetulan ada di sana. Jika Anda meminta semua catatan dan kode Anda berfungsi, maka Anda akan cenderung untuk melanjutkan. Nanti jika sesuatu berubah dan sekarang kode Anda tidak berfungsi, akan sulit untuk men-debug banyak pertanyaan dan fungsi mencari nilai yang seharusnya ada di sana dan satu-satunya referensi nilai adalah *.
Juga dalam pendekatan N-tiered, masih lebih baik untuk mengisolasi gangguan skema database ke tingkat data. Jika tingkat data Anda melewati * ke logika bisnis dan kemungkinan besar pada tingkat presentasi, Anda memperluas cakupan debug Anda secara eksponensial.
sumber
select *
jauh lebih buruk!karena jika tabel mendapat kolom baru maka Anda mendapatkan semua itu bahkan ketika Anda tidak membutuhkannya. dengan
varchars
ini bisa menjadi banyak data tambahan yang perlu diajak bepergian dari DBbeberapa optimasi DB juga dapat mengekstrak catatan panjang tidak tetap ke file terpisah untuk mempercepat akses ke bagian panjang tetap, menggunakan pilih * mengalahkan tujuan dari itu
sumber
Selain overhead, sesuatu yang ingin Anda hindari di tempat pertama, saya akan mengatakan bahwa sebagai seorang programmer Anda tidak bergantung pada urutan kolom yang ditentukan oleh administrator database. Anda memilih setiap kolom bahkan jika Anda membutuhkan semuanya.
sumber
Saya tidak melihat alasan mengapa Anda tidak boleh menggunakan untuk tujuan membangun - mengambil semua kolom dari database. Saya melihat tiga kasus:
Kolom ditambahkan dalam database dan Anda juga menginginkannya dalam kode. a) Dengan * akan gagal dengan pesan yang tepat. b) Tanpa * akan berfungsi, tetapi tidak akan melakukan apa yang Anda harapkan sangat buruk.
Kolom ditambahkan dalam database dan Anda tidak menginginkannya dalam kode. a) Dengan * akan gagal; ini berarti * tidak lagi berlaku karena semantiknya berarti "mengambil semua". b) Tanpa * akan bekerja.
Kolom dihapus Kode akan gagal baik.
Sekarang kasus yang paling umum adalah kasus 1 (karena Anda menggunakan * yang berarti semua yang paling Anda inginkan); tanpa * Anda dapat memiliki kode yang berfungsi dengan baik tetapi tidak melakukan apa yang diharapkan, jauh lebih buruk daripada yang gagal dengan pesan kesalahan yang tepat .
Saya tidak mempertimbangkan kode yang mengambil data kolom berdasarkan indeks kolom yang rawan kesalahan menurut saya. Jauh lebih logis untuk mengambilnya berdasarkan nama kolom.
sumber
Select *
dimaksudkan lebih sebagai kenyamanan untuk permintaan ad-hoc, bukan untuk tujuan pengembangan aplikasi. Atau untuk digunakan dalam konstruksi statistik sepertiselect count(*)
yang memungkinkan mesin kueri memutuskan apakah akan menggunakan indeks, indeks mana yang akan digunakan dan seterusnya dan Anda tidak mengembalikan data kolom yang sebenarnya. Atau untuk digunakan dalam klausa sepertiwhere exists( select * from other_table where ... )
, yang sekali lagi merupakan undangan ke mesin kueri untuk memilih jalur paling efisien sendiri dan subquery hanya digunakan untuk membatasi hasil dari kueri utama. Dllselect *
memiliki semantik untuk mengambil semua kolom; jika aplikasi Anda benar-benar membutuhkan ini, saya tidak melihat alasan mengapa tidak menggunakannya. Bisakah Anda menunjuk ke beberapa referensi (Oracle, IBM, Microsoft dll.) Yang menyebutkan tujuan yangselect *
dibangun bukan untuk mengambil semua kolom?select *
ada untuk mengambil semua kolom ... sebagai fitur kenyamanan, untuk query ad-hoc, bukan karena itu ide bagus dalam perangkat lunak produksi. Alasannya sudah tercakup dengan cukup baik dalam jawaban di halaman ini, itulah sebabnya saya tidak membuat jawaban terperinci saya sendiri: •) Masalah kinerja, berulang kali menyusun data melalui jaringan yang tidak pernah Anda gunakan, •) masalah dengan kolom alias, •) kegagalan optimisasi rencana permintaan (kegagalan untuk menggunakan indeks dalam beberapa kasus), •) server I / O yang tidak efisien dalam kasus di mana pemilihan terbatas hanya dapat menggunakan indeks, dll.select *
dalam aplikasi produksi yang sebenarnya, tetapi sifat dari kasus tepi adalah bahwa itu bukan kasus umum . :-)select *
; apa yang saya katakan jika Anda benar-benar membutuhkan semua kolom, saya tidak melihat alasan mengapa Anda tidak boleh menggunakanselect *
; walaupun sedikit harus ada skenario di mana semua kolom dibutuhkan.Pikirkan seperti ini ... jika Anda kueri semua kolom dari tabel yang hanya memiliki beberapa string kecil atau bidang angka, total data itu 100 ribu. Latihan yang buruk, tapi itu akan berhasil. Sekarang tambahkan satu bidang yang menampung, katakanlah, gambar atau dokumen kata 10MB. sekarang kueri berkinerja cepat Anda segera dan secara misterius mulai berkinerja buruk, hanya karena bidang telah ditambahkan ke tabel ... Anda mungkin tidak memerlukan elemen data yang sangat besar, tetapi karena Anda telah melakukannya,
Select * from Table
Anda tetap mendapatkannya.sumber