Dalam SQL Server 2012, (atau versi apa pun dari 2005 ke atas), menggunakan SELECT *...
hanya masalah kinerja yang mungkin dalam pernyataan SELECT tingkat atas dari kueri.
Jadi BUKAN masalah di Views (*), di subqueries, di klausa ADA, di CTE, atau di SELECT COUNT(*)..
dll, dll. Perhatikan, bahwa ini mungkin juga berlaku untuk Oracle, dan DB2, dan mungkin PostGres (tidak yakin) , tetapi sangat mungkin bahwa itu masih menjadi masalah dalam banyak kasus untuk MySql.
Untuk memahami mengapa (dan mengapa itu masih bisa menjadi masalah dalam SELECT tingkat atas), akan sangat membantu untuk memahami mengapa itu pernah menjadi masalah, yang karena menggunakan SELECT *..
cara " mengembalikan SEMUA kolom ". Secara umum ini akan mengembalikan lebih banyak data daripada yang Anda inginkan, yang jelas dapat menghasilkan lebih banyak IO, baik disk maupun jaringan.
Apa yang kurang jelas adalah bahwa ini juga membatasi indeks apa dan rencana kueri yang dapat digunakan oleh pengoptimal SQL, karena ia tahu bahwa pada akhirnya harus mengembalikan semua kolom data. Jika sebelumnya dapat mengetahui bahwa Anda hanya menginginkan kolom tertentu, maka seringkali dapat menggunakan rencana kueri yang lebih efisien dengan memanfaatkan indeks yang hanya memiliki kolom tersebut. Untungnya ada cara untuk mengetahui hal ini sebelumnya, yaitu bagi Anda untuk secara eksplisit menentukan kolom yang Anda inginkan dalam daftar kolom. Tetapi ketika Anda menggunakan "*", Anda menolak ini demi "berikan saja segalanya kepada saya, saya akan mencari tahu apa yang saya butuhkan."
Ya, ada juga CPU tambahan dan penggunaan memori untuk memproses setiap kolom, tetapi hampir selalu kecil dibandingkan dengan dua hal ini: disk tambahan yang signifikan dan bandwidth jaringan yang diperlukan untuk kolom yang tidak Anda butuhkan, dan harus menggunakan lebih sedikit rencana kueri yang dioptimalkan karena harus menyertakan setiap kolom.
Jadi apa yang berubah? Pada dasarnya, Pengoptimal SQL berhasil memasukkan fitur yang disebut "Optimasi Kolom" yang hanya berarti, bahwa mereka sekarang dapat mencari tahu di sub-kueri tingkat lebih rendah jika Anda akan benar-benar menggunakan kolom di tingkat atas permintaan.
Hasilnya adalah tidak masalah lagi jika Anda menggunakan 'SELECT * ..' di tingkat bawah / dalam dari sebuah kueri. Alih-alih, yang sebenarnya penting adalah apa yang ada dalam daftar kolom SELECT tingkat atas. Kecuali Anda menggunakan SELECT *..
di bagian atas, maka sekali lagi, harus mengasumsikan bahwa Anda ingin SEMUA kolom, dan karenanya tidak dapat menggunakan optimasi kolom secara efektif.
(* - perhatikan bahwa ada masalah kecil yang mengikat di Tampilan dengan di *
mana mereka tidak selalu mendaftarkan perubahan dalam daftar kolom ketika "*" digunakan. Ada cara lain untuk mengatasinya dan itu tidak mempengaruhi kinerja.)
Secara fisik dan bermasalah diizinkan untuk menggunakan
select * from table
, namun, itu ide yang buruk. Mengapa?Pertama-tama, Anda akan menemukan bahwa Anda mengembalikan kolom yang tidak Anda butuhkan (resource resource).
Kedua, ini akan memakan waktu lebih lama pada tabel besar daripada memberi nama kolom karena ketika Anda memilih *, Anda benar-benar memilih nama kolom dari database dan mengatakan "berikan saya data yang terkait dengan kolom yang memiliki nama dalam daftar lainnya ini . " Meskipun ini cepat untuk programmer, bayangkan melakukan ini mencari di komputer bank yang mungkin memiliki ratusan ribu pencarian dalam satu menit.
Ketiga, melakukan ini sebenarnya membuat lebih sulit bagi pengembang. Seberapa sering Anda perlu membalik-balik dari SSMS ke VS untuk mendapatkan semua nama kolom?
Keempat, itu pertanda program malas dan saya tidak berpikir bahwa pengembang mana pun menginginkan reputasi itu.
sumber
Ini bisa menjadi masalah jika Anda memasukkan
Select * ...
kode ke dalam sebuah program, karena, seperti yang ditunjukkan sebelumnya, database mungkin berubah seiring waktu dan memiliki lebih banyak kolom daripada yang Anda harapkan saat Anda menulis kueri. Ini dapat menyebabkan kegagalan program (kasus terbaik) atau program mungkin berjalan dengan cara yang meriah dan merusak beberapa data karena itu melihat nilai-nilai bidang yang tidak ditulis untuk ditangani. Singkatnya, kode produksi harus SELALU menentukan bidang yang akan dikembalikan dalamSELECT
.Karena itu, saya memiliki sedikit masalah ketika
Select *
bagian dariEXISTS
klausa, karena semua yang akan dikembalikan ke program adalah boolean yang menunjukkan keberhasilan atau kegagalan pemilihan. Orang lain mungkin tidak setuju dengan pendirian ini dan saya menghargai pendapat mereka tentang hal itu. MUNGKIN menjadi sedikit kurang efisien untuk kodeSelect *
daripada kode 'Pilih 1' dalamEXISTS
klausa, tapi saya tidak berpikir ada bahaya kerusakan data.sumber
Banyak jawaban mengapa
select *
salah, jadi saya akan membahas ketika saya merasa itu benar atau setidaknya OK.1) Dalam EXISTS, konten bagian SELECT dari kueri diabaikan, sehingga Anda bahkan dapat menulis
SELECT 1/0
dan itu tidak akan salah.EXISTS
hanya memverifikasi bahwa beberapa data akan kembali dan mengembalikan boolean berdasarkan itu.2) Ini mungkin memulai badai api, tapi saya suka menggunakan
select *
di tabel histori saya pemicu. Olehselect *
, itu mencegah tabel utama dari mendapatkan kolom baru tanpa menambahkan kolom ke tabel sejarah juga dengan kesalahan segera ketika dimasukkan / diperbarui / dihapus ke dalam tabel utama. Ini telah mencegah beberapa kali pengembang menambahkan kolom dan lupa menambahkannya ke tabel riwayat.sumber
SELECT 1
karena itu paling jelas memberi tahu pengelola kode tentang niat Anda di masa depan. Itu bukan keharusan , tetapi jika saya melihatnya... WHERE EXISTS (SELECT 1 ...)
dengan jelas mengumumkan dirinya sebagai ujian kebenaran.SELECT 1
berdasarkan mitos bahwa kinerja akan lebih baik daripadaSELECT *
. Namun, kedua opsi tersebut dapat diterima. Tidak ada perbedaan dalam kinerja karena cara pengoptimal menangani EXIS. Juga tidak ada perbedaan dalam keterbacaan karena kata "EXISTS" yang dengan jelas mengumumkan ujian kebenaran.Column8
ke tabel utama melupakan tabel sejarah. Pengembang menulis banyak kode yang ditransfer ke Kolom 8. Kemudian ia menambahkanColumn9
ke tabel utama; ingat kali ini juga menambah sejarah. Kemudian ketika pengujian dia menyadari bahwa dia lupa untuk menambahColumn9
riwayat (terima kasih untuk teknik deteksi kesalahan Anda), dan segera menambahkannya. Sekarang pelatuk tampaknya berfungsi, tetapi data di kolom 8 & 9 tercampur dalam sejarah. : S