Jika saya hanya memerlukan 2/3 kolom dan saya melakukan kueri SELECT *
alih-alih memberikan kolom tersebut dalam kueri pemilihan, apakah ada penurunan kinerja terkait lebih / kurang I / O atau memori?
Overhead jaringan mungkin ada jika saya memilih * tanpa perlu.
Tetapi dalam operasi pemilihan, apakah mesin database selalu menarik atomic tuple dari disk, atau apakah itu hanya menarik kolom yang diminta dalam operasi pemilihan?
Jika selalu menarik tupel maka overhead I / O sama.
Pada saat yang sama, mungkin ada konsumsi memori untuk menghapus kolom yang diminta dari tupel, jika menarik tupel.
Jadi jika demikian, pilih someColumn akan memiliki lebih banyak overhead memori daripada pilih *
sql
performance
Neel Basu
sumber
sumber
SELECT
kueri dijalankan / diproses berbeda dari database ke database.CREATE VIEW foo_view AS SELECT * FROM foo;
, kemudian menambahkan kolom ke tabel foo nanti, kolom tersebut tidak akan secara otomatis muncul di foo_view seperti yang diharapkan. Dengan kata lain,*
dalam konteks ini hanya mengembang sekali (pada waktu pembuatan tampilan), bukan per SELECT. Karena komplikasi yang timbul dari ALTER TABLE, saya akan mengatakan bahwa (dalam praktiknya)*
Dianggap Berbahaya.Jawaban:
Itu selalu menarik tupel (kecuali dalam kasus di mana tabel telah tersegmentasi secara vertikal - dipecah menjadi potongan kolom), jadi, untuk menjawab pertanyaan yang Anda ajukan, tidak masalah dari perspektif kinerja. Namun, karena banyak alasan lainnya, (di bawah) Anda harus selalu memilih kolom yang Anda inginkan secara spesifik, menurut nama.
Itu selalu menarik tupel, karena (di setiap vendor, RDBMS yang saya kenal), struktur penyimpanan pada disk yang mendasari untuk semuanya (termasuk data tabel) didasarkan pada Halaman I / O yang ditentukan (di SQL Server untuk misalnya, setiap Halaman adalah 8 kilobyte). Dan setiap I / O baca atau tulis adalah berdasarkan Halaman .. Yaitu, setiap menulis atau membaca adalah Halaman data yang lengkap.
Karena kendala struktural yang mendasari ini, konsekuensinya adalah bahwa Setiap baris data dalam database harus selalu dalam satu dan hanya satu halaman. Ini tidak dapat menjangkau beberapa Halaman data (kecuali untuk hal-hal khusus seperti blob, di mana data blob sebenarnya disimpan dalam potongan Halaman terpisah, dan kolom baris tabel aktual hanya mendapat penunjuk ...). Tetapi pengecualian ini hanya itu, pengecualian, dan umumnya tidak berlaku kecuali dalam kasus khusus (untuk jenis data khusus, atau pengoptimalan tertentu untuk keadaan khusus)
Bahkan dalam kasus khusus ini, umumnya, baris tabel sebenarnya dari data itu sendiri (yang berisi penunjuk ke data aktual untuk Blob, atau apa pun), itu harus disimpan di satu Halaman IO ...
PENGECUALIAN. Satu-satunya tempat di mana
Select *
OK, adalah di sub-kueri setelah klausa predikatExists
atauNot Exists
, seperti di:EDIT: Untuk mengatasi komentar @Mike Sherer, Ya itu benar, baik secara teknis, dengan sedikit definisi untuk kasus khusus Anda, dan secara estetika. Pertama, bahkan ketika kumpulan kolom yang diminta adalah bagian dari yang disimpan dalam beberapa indeks, prosesor kueri harus mengambil setiap kolom yang disimpan dalam indeks itu, bukan hanya yang diminta, untuk alasan yang sama - SEMUA I / O harus dilakukan di halaman, dan data indeks disimpan di Halaman IO seperti data tabel. Jadi jika Anda mendefinisikan "tuple" untuk halaman indeks sebagai kumpulan kolom yang disimpan dalam indeks, pernyataan tersebut masih benar.
dan pernyataan itu benar secara estetika karena intinya adalah ia mengambil data berdasarkan apa yang disimpan di halaman I / O, bukan pada apa yang Anda minta, dan ini benar apakah Anda mengakses halaman I / O tabel dasar atau indeks Halaman I / O.
Untuk alasan lain tidak menggunakan
Select *
, lihat MengapaSELECT *
dianggap berbahaya? :sumber
select *
akan memiliki lebih sedikit overhead memori daripadaselect column
tetapi overhead I / O yang sama. jadi Jika kita meninggalkan overhead jaringan.select *
jika overhead kurang dari ituselect column
Ada beberapa alasan mengapa Anda tidak boleh (tidak pernah) menggunakan
SELECT *
kode produksi:karena Anda tidak memberikan petunjuk apa pun kepada database Anda tentang apa yang Anda inginkan, pertama-tama perlu memeriksa definisi tabel untuk menentukan kolom pada tabel itu. Pencarian itu akan memakan waktu - tidak banyak dalam satu kueri - tetapi bertambah seiring waktu
jika Anda hanya membutuhkan 2/3 kolom, Anda memilih 1/3 terlalu banyak data yang perlu diambil dari disk dan dikirim melalui jaringan
jika Anda mulai mengandalkan aspek data tertentu, misalnya urutan kolom yang dikembalikan, Anda bisa mendapatkan kejutan yang tidak menyenangkan setelah tabel diatur ulang dan kolom baru ditambahkan (atau kolom yang sudah ada dihapus)
di SQL Server (tidak yakin tentang database lain), jika Anda memerlukan subset kolom, selalu ada kemungkinan indeks non-cluster mungkin menutupi permintaan itu (berisi semua kolom yang diperlukan). Dengan a
SELECT *
, Anda menyerah pada kemungkinan itu sejak awal. Dalam kasus khusus ini, data akan diambil dari halaman indeks (jika halaman tersebut berisi semua kolom yang diperlukan) dan dengan demikian I / O disk dan overhead memori akan jauh lebih sedikit dibandingkan dengan melakukanSELECT *....
kueri.Ya, dibutuhkan sedikit lebih banyak pengetikan pada awalnya (alat seperti SQL Prompt untuk SQL Server bahkan akan membantu Anda di sana) - tetapi ini benar-benar salah satu kasus di mana ada aturan tanpa pengecualian: jangan pernah menggunakan SELECT * dalam kode produksi Anda. PERNAH.
sumber
Where Exists (Select * From ...
) penggunaanSelect *
tentu tidak menjadi masalah, dan di beberapa kalangan dianggap sebagai praktik terbaik.IF EXISTS(SELECT *...
ini adalah kasus khusus - karena di sana, tidak ada data yang benar-benar diambil, tetapi ini hanya pemeriksaan keberadaan, SELECT * tidak menjadi masalah di sana ...Anda harus selalu hanya
select
kolom yang benar-benar Anda butuhkan. Tidak pernah kurang efisien untuk memilih lebih sedikit daripada lebih banyak, dan Anda juga mengalami lebih sedikit efek samping yang tidak terduga - seperti mengakses kolom hasil Anda di sisi klien dengan indeks, kemudian membuat indeks tersebut menjadi salah dengan menambahkan kolom baru ke tabel.[edit]: Mengakses yang dimaksud. Otak bodoh masih bangun.
sumber
SELECT *
dengannya.Kecuali Anda menyimpan gumpalan besar, kinerja bukanlah masalah. Alasan utama untuk tidak menggunakan SELECT * adalah jika Anda menggunakan baris yang dikembalikan sebagai tupel, kolom kembali dalam urutan apa pun yang ditentukan oleh skema, dan jika itu berubah, Anda harus memperbaiki semua kode Anda.
Di sisi lain, jika Anda menggunakan akses gaya kamus maka tidak masalah urutan kolom kembali karena Anda selalu mengaksesnya berdasarkan nama.
sumber
Ini segera membuat saya berpikir tentang tabel yang saya gunakan yang berisi kolom tipe
blob
; biasanya berisi gambar JPEG, berukuran beberapaMb
detik.Tak perlu dikatakan saya tidak melakukan
SELECT
kolom itu kecuali saya benar - benar membutuhkannya. Memiliki data itu mengambang - terutama ketika saya memilih mulitple baris - hanya merepotkan.Namun, saya akui bahwa saya biasanya meminta semua kolom dalam tabel.
sumber
Selama pemilihan SQL, DB akan selalu merujuk ke metadata untuk tabel, terlepas dari apakah itu SELECT * untuk SELECT a, b, c ... Why? Karena disitulah informasi tentang struktur dan tata letak tabel pada sistem berada.
Itu harus membaca informasi ini karena dua alasan. Satu, untuk sekadar menyusun pernyataan. Ini perlu memastikan bahwa Anda menentukan tabel yang ada setidaknya. Selain itu, struktur database mungkin telah berubah sejak terakhir kali sebuah pernyataan dieksekusi.
Sekarang, jelas, metadata DB di-cache di sistem, tetapi masih pemrosesan yang perlu dilakukan.
Selanjutnya, metadata digunakan untuk menghasilkan rencana kueri. Ini terjadi setiap kali pernyataan dikompilasi juga. Sekali lagi, ini berjalan terhadap metadata yang di-cache, tetapi itu selalu dilakukan.
Satu-satunya saat pemrosesan ini tidak selesai adalah ketika DB menggunakan kueri yang telah dikompilasi sebelumnya, atau telah menyimpan kueri sebelumnya ke cache. Ini adalah argumen untuk menggunakan parameter binding daripada SQL literal. "SELECT * FROM TABLE WHERE key = 1" adalah kueri yang berbeda dari "SELECT * FROM TABLE WHERE key =?" dan "1" terikat saat menelepon.
DB sangat bergantung pada cache halaman untuk pekerjaan di sana. Banyak DB modern cukup kecil untuk muat sepenuhnya dalam memori (atau, mungkin harus saya katakan, memori modern cukup besar untuk memuat banyak DB). Maka biaya I / O utama Anda di bagian belakang adalah logging dan flushes halaman.
Namun, jika Anda masih menggunakan disk untuk DB Anda, pengoptimalan utama yang dilakukan oleh banyak sistem adalah dengan mengandalkan data dalam indeks, bukan tabel itu sendiri.
Jika Anda memiliki:
Kemudian jika Anda melakukan "SELECT id, name FROM customer WHERE id = 1", kemungkinan besar DB Anda akan menarik data ini dari indeks, bukan dari tabel.
Mengapa? Kemungkinan akan tetap menggunakan indeks untuk memenuhi kueri (vs pemindaian tabel), dan meskipun 'nama' tidak digunakan di klausa where, indeks tersebut akan tetap menjadi opsi terbaik untuk kueri.
Sekarang database memiliki semua data yang dibutuhkan untuk memenuhi kueri, jadi tidak ada alasan untuk membuka halaman tabel itu sendiri. Menggunakan hasil indeks dalam lalu lintas disk yang lebih sedikit karena Anda memiliki kepadatan baris yang lebih tinggi dalam indeks vs tabel pada umumnya.
Ini adalah penjelasan bergelombang tentang teknik optimasi spesifik yang digunakan oleh beberapa database. Banyak yang memiliki beberapa teknik optimasi dan tuning.
Pada akhirnya, SELECT * berguna untuk kueri dinamis yang harus Anda ketik secara manual, saya tidak akan pernah menggunakannya untuk "kode sebenarnya". Identifikasi kolom individual memberi DB lebih banyak informasi yang dapat digunakan untuk mengoptimalkan kueri, dan memberi Anda kontrol yang lebih baik dalam kode Anda terhadap perubahan skema, dll.
sumber
Saya rasa tidak ada jawaban pasti untuk pertanyaan Anda, karena Anda telah mempertimbangkan kinerja dan fasilitas pemeliharaan aplikasi Anda.
Select column
lebih berkinerjaselect *
, tetapi jika Anda mengembangkan sistem objek yang berorientasi, maka Anda akan menyukai penggunaanobject.properties
dan Anda dapat memerlukan properti di bagian mana pun dari aplikasi, kemudian Anda perlu menulis lebih banyak metode untuk mendapatkan properti dalam situasi khusus jika Anda tidak menggunakanselect *
dan mengisi semua properti. Aplikasi Anda perlu memiliki kinerja yang baik menggunakanselect *
dan dalam beberapa kasus Anda perlu menggunakan kolom pilih untuk meningkatkan kinerja. Maka Anda akan memiliki yang lebih baik dari dua dunia, fasilitas untuk menulis dan memelihara aplikasi dan kinerja saat Anda membutuhkan kinerja.sumber
Jawaban yang diterima di sini salah. Saya menemukan ini ketika pertanyaan lain ditutup sebagai duplikat dari ini (ketika saya masih menulis jawaban saya - grr - maka SQL di bawah ini merujuk pada pertanyaan lain).
Anda harus selalu menggunakan atribut SELECT, atribut .... NOT SELECT *
Ini terutama untuk masalah kinerja.
Bukan contoh yang sangat berguna. Pertimbangkan sebagai gantinya:
Jika ada indeks pada (nama, telepon) maka kueri dapat diselesaikan tanpa harus mencari nilai yang relevan dari tabel - ada indeks penutup .
Selanjutnya, misalkan tabel memiliki BLOB yang berisi gambar pengguna, dan CV yang diunggah, dan spreadsheet ... menggunakan SELECT * akan menarik semua informasi ini kembali ke buffer DBMS (memaksa keluar informasi berguna lainnya dari cache). Kemudian semuanya akan dikirim ke klien menggunakan waktu habis di jaringan dan memori di klien untuk data yang berlebihan.
Ini juga dapat menyebabkan masalah fungsional jika klien mengambil data sebagai array yang disebutkan (seperti mysql_fetch_array ($ x, MYSQL_NUM)) PHP. Mungkin ketika kode itu tertulis 'telephone' adalah kolom ketiga yang dikembalikan oleh SELECT *, tapi kemudian seseorang datang dan memutuskan untuk menambahkan alamat email ke tabel, ditempatkan sebelum 'telephone'. Bidang yang diinginkan sekarang bergeser ke kolom ke-4.
sumber
Ada alasan untuk melakukan sesuatu dengan cara apa pun. Saya banyak menggunakan SELECT * di PostgreSQL karena ada banyak hal yang dapat Anda lakukan dengan SELECT * di PostgreSQL yang tidak dapat Anda lakukan dengan daftar kolom eksplisit, terutama jika dalam prosedur tersimpan. Demikian pula di Informix, SELECT * di atas pohon tabel yang diwariskan dapat memberi Anda baris bergerigi sementara daftar kolom eksplisit tidak bisa karena kolom tambahan dalam tabel anak juga dikembalikan.
Alasan utama mengapa saya melakukan ini di PostgreSQL adalah karena ini memastikan bahwa saya mendapatkan tipe yang dibentuk dengan baik khusus untuk tabel. Ini memungkinkan saya untuk mengambil hasilnya dan menggunakannya sebagai tipe tabel di PostgreSQL. Ini juga memungkinkan lebih banyak opsi dalam kueri daripada daftar kolom kaku.
Di sisi lain, daftar kolom yang kaku memberi Anda pemeriksaan tingkat aplikasi bahwa skema db tidak berubah dengan cara tertentu dan ini dapat membantu. (Saya melakukan pemeriksaan seperti itu di tingkat lain.)
Adapun kinerja, saya cenderung menggunakan TAMPILAN dan prosedur tersimpan mengembalikan tipe (dan kemudian daftar kolom di dalam prosedur yang tersimpan). Ini memberi saya kendali atas jenis apa yang dikembalikan.
Namun perlu diingat saya menggunakan SELECT * biasanya terhadap lapisan abstraksi daripada tabel dasar.
sumber
Referensi diambil dari artikel ini:
Tanpa PILIH *: Saat Anda menggunakan "PILIH *" pada saat itu Anda memilih lebih banyak kolom dari database dan beberapa kolom ini mungkin tidak digunakan oleh aplikasi Anda. Ini akan menimbulkan biaya dan beban tambahan pada sistem database dan lebih banyak perjalanan data di seluruh jaringan.
Dengan PILIH *: Jika Anda memiliki persyaratan khusus dan menciptakan lingkungan dinamis ketika menambah atau menghapus kolom secara otomatis ditangani oleh kode aplikasi. Dalam kasus khusus ini Anda tidak perlu mengubah aplikasi dan kode database dan ini secara otomatis akan mempengaruhi lingkungan produksi. Dalam hal ini Anda dapat menggunakan “PILIH *”.
sumber
Hanya untuk menambahkan nuansa pada diskusi yang tidak saya lihat di sini: Dalam hal I / O, jika Anda menggunakan database dengan penyimpanan berorientasi kolom, Anda dapat melakukan BANYAK lebih sedikit I / O jika Anda hanya menanyakan secara pasti. kolom. Saat kami pindah ke SSD, manfaatnya mungkin sedikit lebih kecil vs. penyimpanan berorientasi baris tetapi ada a) hanya membaca blok yang berisi kolom yang Anda pedulikan b) kompresi, yang umumnya sangat mengurangi ukuran data pada disk dan karenanya volume data yang dibaca dari disk.
Jika Anda tidak terbiasa dengan penyimpanan berorientasi kolom, satu implementasi untuk Postgres berasal dari Citus Data, yang lain adalah Greenplum, Paraccel lain, yang lain (secara bebas) adalah Amazon Redshift. Untuk MySQL ada Infobright, InfiniDB yang sekarang hampir tidak berfungsi. Penawaran komersial lainnya termasuk Vertica dari HP, Sybase IQ, Teradata ...
sumber
sama
sumber