Inti dari kutipan dari tidak mengoptimalkan sebelum waktunya adalah menggunakan kode yang sederhana dan lugas, lalu menggunakan profiler untuk menunjukkan hot spot, yang kemudian dapat Anda optimalkan agar efisien.
Ketika Anda menggunakan pilih * Anda membuatnya tidak mungkin untuk membuat profil, oleh karena itu Anda tidak menulis kode yang jelas & lugas dan Anda bertentangan dengan semangat kutipan. select *
adalah anti-pola.
Jadi memilih kolom bukanlah pengoptimalan yang prematur. Beberapa hal di luar kepala saya ....
- Jika Anda menentukan kolom dalam pernyataan SQL, mesin eksekusi SQL akan error jika kolom tersebut dihapus dari tabel dan kueri dijalankan.
- Anda dapat dengan mudah memindai kode di mana kolom itu digunakan.
- Anda harus selalu menulis pertanyaan untuk mengembalikan informasi yang paling sedikit.
- Seperti yang disebutkan orang lain jika Anda menggunakan akses kolom ordinal, Anda tidak boleh menggunakan pilih *
- Jika pernyataan SQL Anda menggabungkan tabel, pilih * memberi Anda semua kolom dari semua tabel yang digabungkan
Konsekuensinya adalah bahwa menggunakan select *
...
- Kolom yang digunakan oleh aplikasi tidak tembus cahaya
- DBA dan profiler kuerinya tidak dapat membantu kinerja aplikasi Anda yang buruk
- Kode menjadi lebih rapuh saat terjadi perubahan
- Database dan jaringan Anda bermasalah karena membawa kembali terlalu banyak data (I / O)
- Pengoptimalan mesin database minimal saat Anda mengembalikan semua data apa pun (logis).
Menulis SQL yang benar semudah menulis Select *
. Jadi, orang yang benar-benar malas menulis SQL yang benar karena mereka tidak ingin mengunjungi kembali kode tersebut dan mencoba mengingat apa yang mereka lakukan saat melakukannya. Mereka tidak ingin menjelaskan kepada DBA tentang setiap bit kode. Mereka tidak ingin menjelaskan kepada klien mereka mengapa aplikasi berjalan seperti anjing.
Jika kode Anda bergantung pada kolom yang berada dalam urutan tertentu, kode Anda akan rusak ketika ada perubahan pada tabel. Selain itu, Anda mungkin mengambil terlalu banyak dari tabel saat memilih *, terutama jika ada bidang biner di tabel.
Hanya karena Anda menggunakan semua kolom sekarang, itu tidak berarti orang lain tidak akan menambahkan kolom tambahan ke tabel.
Ini juga menambahkan overhead ke cache eksekusi rencana karena harus mengambil meta data tentang tabel untuk mengetahui kolom apa yang ada di *.
sumber
Salah satu alasan utamanya adalah jika Anda pernah menambah / menghapus kolom dari tabel Anda, setiap kueri / prosedur yang membuat panggilan SELECT * sekarang akan mendapatkan lebih banyak atau lebih sedikit kolom data daripada yang diharapkan.
sumber
Secara tidak langsung, Anda melanggar aturan modularitas tentang penggunaan pengetikan yang ketat jika memungkinkan. Eksplisit hampir secara universal lebih baik.
Bahkan jika Anda sekarang membutuhkan setiap kolom dalam tabel, lebih banyak lagi dapat ditambahkan nanti yang akan ditarik ke bawah setiap kali Anda menjalankan kueri dan dapat merusak kinerja. Itu merusak kinerja karena
Kapan harus menggunakan pilih *
Ketika Anda secara eksplisit MEMBUTUHKAN setiap kolom dalam tabel, bukan membutuhkan setiap kolom dalam tabel YANG ADA SAAT ANDA MENULIS KUERI. Misalnya, jika Anda menulis aplikasi manajemen DB yang perlu menampilkan seluruh konten tabel (apa pun yang terjadi), Anda mungkin menggunakan pendekatan itu.
sumber
SELECT *
adalah saat Anda melakukan kueri pengujian menggunakan klien db.Ada beberapa alasan:
Catatan: Saya memilih INTEGER pada contoh di atas karena mereka memiliki ukuran tetap 4 byte.
sumber
Jika aplikasi Anda mendapatkan data dengan SELECT * dan struktur tabel dalam database diubah (misalnya kolom dihapus), aplikasi Anda akan gagal di setiap tempat yang Anda rujuk ke bidang yang hilang. Jika Anda malah menyertakan semua kolom dalam kueri, aplikasi Anda akan rusak di (semoga) satu tempat di mana Anda awalnya mendapatkan data, membuat perbaikan lebih mudah.
Meskipun demikian, ada sejumlah situasi di mana SELECT * diinginkan. Salah satunya adalah situasi yang saya hadapi sepanjang waktu, di mana saya perlu mereplikasi seluruh tabel ke database lain (seperti SQL Server ke DB2, misalnya). Lain adalah aplikasi yang ditulis untuk menampilkan tabel secara umum (yaitu tanpa pengetahuan tentang tabel tertentu).
sumber
Saya benar-benar melihat perilaku aneh ketika saya menggunakan
select *
tampilan di SQL Server 2005.Jalankan kueri berikut dan Anda akan melihat apa yang saya maksud.
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[starTest]') AND type in (N'U')) DROP TABLE [dbo].[starTest] CREATE TABLE [dbo].[starTest]( [id] [int] IDENTITY(1,1) NOT NULL, [A] [varchar](50) NULL, [B] [varchar](50) NULL, [C] [varchar](50) NULL ) ON [PRIMARY] GO insert into dbo.starTest select 'a1','b1','c1' union all select 'a2','b2','c2' union all select 'a3','b3','c3' go IF EXISTS (SELECT * FROM sys.views WHERE object_id = OBJECT_ID(N'[dbo].[vStartest]')) DROP VIEW [dbo].[vStartest] go create view dbo.vStartest as select * from dbo.starTest go go IF EXISTS (SELECT * FROM sys.views WHERE object_id = OBJECT_ID(N'[dbo].[vExplicittest]')) DROP VIEW [dbo].[vExplicittest] go create view dbo.[vExplicittest] as select a,b,c from dbo.starTest go select a,b,c from dbo.vStartest select a,b,c from dbo.vExplicitTest IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[starTest]') AND type in (N'U')) DROP TABLE [dbo].[starTest] CREATE TABLE [dbo].[starTest]( [id] [int] IDENTITY(1,1) NOT NULL, [A] [varchar](50) NULL, [B] [varchar](50) NULL, [D] [varchar](50) NULL, [C] [varchar](50) NULL ) ON [PRIMARY] GO insert into dbo.starTest select 'a1','b1','d1','c1' union all select 'a2','b2','d2','c2' union all select 'a3','b3','d3','c3' select a,b,c from dbo.vStartest select a,b,c from dbo.vExplicittest
Bandingkan hasil dari 2 pernyataan pemilihan terakhir. Saya yakin apa yang akan Anda lihat adalah hasil dari Pilih * kolom referensi berdasarkan indeks, bukan nama.
Jika Anda membangun kembali tampilan itu akan berfungsi dengan baik lagi.
EDIT
Saya telah menambahkan pertanyaan terpisah, * "pilih * dari tabel" vs "pilih colA, colB, dll. Dari tabel" perilaku menarik di SQL Server 2005 * untuk melihat perilaku tersebut secara lebih rinci.
sumber
Anda bisa menggabungkan dua tabel dan menggunakan kolom A dari tabel kedua. Jika nanti Anda menambahkan kolom A ke tabel pertama (dengan nama yang sama tetapi mungkin artinya berbeda), kemungkinan besar Anda akan mendapatkan nilai dari tabel pertama dan bukan yang kedua seperti sebelumnya. Itu tidak akan terjadi jika Anda secara eksplisit menentukan kolom yang ingin Anda pilih.
Tentu saja menentukan kolom juga terkadang menyebabkan bug jika Anda lupa menambahkan kolom baru ke setiap klausa pilih. Jika kolom baru tidak diperlukan setiap kali kueri dijalankan, mungkin perlu beberapa saat sebelum bug diketahui.
sumber
Saya mengerti ke mana Anda akan pergi mengenai pengoptimalan prematur, tetapi itu benar-benar hanya sampai pada satu poin. Maksudnya adalah untuk menghindari yang tidak perlu pengoptimalan yang di awal. Apakah tabel Anda tidak terindeks? Apakah Anda akan menggunakan nvarchar (4000) untuk menyimpan kode pos?
Seperti yang ditunjukkan orang lain, ada hal positif lain untuk menentukan setiap kolom yang ingin Anda gunakan dalam kueri (seperti pemeliharaan).
sumber
Saat Anda menentukan kolom, Anda juga mengikat diri Anda ke dalam kumpulan kolom tertentu dan membuat diri Anda kurang fleksibel, membuat Feuerstein berguling, di mana pun dia berada. Hanya pemikiran saja.
sumber
PILIH * tidak selalu jahat. Setidaknya menurut pendapat saya. Saya cukup sering menggunakannya untuk kueri dinamis yang mengembalikan seluruh tabel, ditambah beberapa bidang yang dihitung.
Misalnya, saya ingin menghitung geometri geografis dari tabel "normal", yaitu tabel tanpa bidang geometri, tetapi dengan bidang yang berisi koordinat. Saya menggunakan postgresql, dan ekstensi spasialnya postgis. Tetapi prinsip tersebut berlaku untuk banyak kasus lain.
Sebuah contoh:
tabel tempat, dengan koordinat disimpan dalam bidang berlabel x, y, z:
BUAT tempat TABEL (place_id integer, x numeric (10, 3), y numeric (10, 3), z numeric (10, 3), description varchar);
mari kita beri makan dengan beberapa nilai contoh:
INSERT INTO places (place_id, x, y, z, description) VALUES
(1, 2.295, 48.863, 64, 'Paris, Place de l \' Étoile '),
(2, 2.945, 48.858, 40,' Paris, Tour Eiffel '),
(3, 0,373, 43,958, 90,' Kondom, Cathédrale St-Pierre ');
Saya ingin dapat memetakan isi tabel ini, menggunakan beberapa klien GIS. Cara normal adalah dengan menambahkan bidang geometri ke tabel, dan membangun geometri, berdasarkan koordinat. Tetapi saya lebih suka mendapatkan kueri dinamis: dengan cara ini, ketika saya mengubah koordinat (koreksi, akurasi lebih, dll.), Objek yang dipetakan benar-benar bergerak, secara dinamis. Jadi inilah kueri dengan SELECT * :
BUAT ATAU GANTI TAMPILAN tempat_point SEBAGAI
PILIH *,
GeomFromewkt ('SRID = 4326; POINT (' || x || '' || y || '' || z || ')')
DARI tempat;
Lihat postgis, untuk penggunaan fungsi GeomFromewkt ().
Inilah hasilnya:
PILIH * DARI places_points;
Kolom paling kanan sekarang dapat digunakan oleh program GIS untuk memetakan titik dengan benar.
Saya berharap definisi VIEW dapat disimpan "sebagaimana adanya", dengan *, tetapi ini bukan masalahnya: ini adalah cara penyimpanan internal oleh postgresql:
PILIH places.place_id, places.x, places.y, places.z, places.description, geomfromewkt ((((('SRID = 4326; POINT (' :: text || places.x) || '': : teks) || tempat.y) || '' :: teks) || tempat.z) || ')' :: teks) AS geomfromewkt DARI tempat;
sumber
Bahkan jika Anda menggunakan setiap kolom tetapi mengatasi array baris dengan indeks numerik, Anda akan mengalami masalah jika Anda menambahkan baris lain nanti.
Jadi pada dasarnya ini adalah pertanyaan tentang pemeliharaan! Jika Anda tidak menggunakan * selektor Anda tidak perlu khawatir dengan pertanyaan Anda.
sumber
Memilih hanya kolom yang Anda butuhkan membuat kumpulan data dalam memori lebih kecil dan karenanya membuat aplikasi Anda lebih cepat.
Juga, banyak alat (misalnya prosedur tersimpan) rencana eksekusi permintaan cache juga. Jika Anda nanti menambah atau menghapus kolom (terutama mudah jika Anda memilih dari tampilan), alat akan sering error saat tidak mendapatkan kembali hasil yang diharapkan.
sumber
Itu membuat kode Anda lebih ambigu dan lebih sulit untuk dipertahankan; karena Anda menambahkan data ekstra yang tidak terpakai ke domain, dan tidak jelas mana yang Anda inginkan dan mana yang tidak. (Ini juga menunjukkan bahwa Anda mungkin tidak tahu, atau peduli.)
sumber
Untuk menjawab pertanyaan Anda secara langsung: Jangan gunakan "PILIH *" saat itu membuat kode Anda lebih mudah berubah ke tabel yang mendasarinya. Kode Anda harus rusak hanya jika ada perubahan pada tabel yang secara langsung mempengaruhi persyaratan program Anda.
Aplikasi Anda harus memanfaatkan lapisan abstraksi yang disediakan oleh akses Relasional.
sumber
Saya tidak menggunakan SELECT * hanya karena bagus untuk melihat dan mengetahui kolom apa yang saya ambil.
sumber
Umumnya buruk untuk menggunakan 'pilih *' di dalam tampilan karena Anda akan dipaksa untuk mengkompilasi ulang tampilan jika kolom tabel berubah. Mengubah kolom tabel yang mendasari tampilan Anda akan mendapatkan kesalahan untuk kolom yang tidak ada sampai Anda kembali dan mengkompilasi ulang.
sumber
Tidak apa-apa jika Anda melakukannya
exists(select * ...)
karena tidak pernah diperluas. Jika tidak, itu benar-benar hanya berguna saat menjelajahi tabel dengan pernyataan pilih sementara atau jika Anda memiliki CTE yang ditentukan di atas dan Anda ingin setiap kolom tanpa mengetik semuanya lagi.sumber
Hanya untuk menambahkan satu hal yang tidak disebutkan orang lain.
Select *
mengembalikan semua kolom, seseorang mungkin menambahkan kolom nanti yang Anda tidak ingin pengguna dapat melihatnya seperti yang terakhir memperbarui data atau stempel waktu atau catatan bahwa hanya manajer yang boleh melihat tidak semua pengguna, dll.Selanjutnya, ketika menambahkan kolom, dampak pada kode yang ada harus ditinjau dan dipertimbangkan untuk melihat apakah diperlukan perubahan berdasarkan informasi apa yang disimpan di kolom tersebut. Dengan menggunakan
select *
, tinjauan tersebut akan sering dilewati karena pengembang akan berasumsi bahwa tidak ada yang akan rusak. Dan sebenarnya tidak ada yang secara eksplisit tampak rusak tetapi kueri sekarang mungkin mulai mengembalikan hal yang salah. Hanya karena tidak ada yang secara eksplisit rusak, tidak berarti seharusnya tidak ada perubahan pada kueri.sumber
karena "pilih *" akan membuang memori ketika Anda tidak membutuhkan semua kolom. Tetapi untuk sql server, kinerjanya sama.
sumber