Pertanyaan yang cukup sederhana, mungkin dijawab di suatu tempat, tetapi sepertinya saya tidak dapat membentuk pertanyaan pencarian yang tepat untuk Google ...
Apakah jumlah kolom dalam tabel tertentu memengaruhi kinerja kueri, saat kueri pada subset tabel itu?
Misalnya, jika tabel Foo memiliki 20 kolom, tetapi kueri saya hanya memilih 5 kolom tersebut, apakah memiliki 20 (dibandingkan, katakanlah, 10) kolom mempengaruhi kinerja kueri? Asumsikan untuk kesederhanaan bahwa apa pun dalam klausa WHERE termasuk dalam 5 kolom tersebut.
Saya khawatir tentang penggunaan cache buffer Postgres di samping cache disk sistem operasi. Saya sangat kehilangan pemahaman tentang desain penyimpanan fisik Postgres. Tabel disimpan di beberapa halaman (ukurannya 8k per halaman), tapi saya tidak begitu mengerti bagaimana tuple diatur dari sana. Apakah PG cukup pintar untuk hanya mengambil dari disk data yang terdiri dari 5 kolom itu?
sumber
Jawaban:
Penyimpanan fisik untuk baris dijelaskan dalam dokumen di Layout Halaman Database . Konten kolom untuk baris yang sama semuanya disimpan di halaman disk yang sama, dengan pengecualian khusus konten TOAST (terlalu besar untuk muat dalam satu halaman). Konten diekstraksi secara berurutan dalam setiap baris, seperti yang dijelaskan:
Dalam kasus yang paling sederhana (tanpa kolom TOAST'ed), postgres akan mengambil seluruh baris bahkan jika beberapa kolom diperlukan. Jadi dalam hal ini, jawabannya adalah ya, memiliki lebih banyak kolom mungkin memiliki dampak buruk yang jelas pada cache buffer pembuang, terutama jika konten kolom besar sementara masih di bawah ambang batas TOAST.
Sekarang kasus TOAST: ketika bidang individual melebihi ~ 2kB, mesin menyimpan konten bidang ke dalam tabel fisik yang terpisah. Itu juga ikut berperan ketika seluruh baris tidak masuk ke dalam sebuah halaman (8kB secara default): beberapa bidang dipindahkan ke penyimpanan TOAST. Doc mengatakan:
Konten TOAST tidak diambil ketika tidak diperlukan secara eksplisit, sehingga pengaruhnya terhadap jumlah total halaman yang akan diambil kecil (beberapa byte per kolom). Ini menjelaskan hasil dalam jawaban @ dezso.
Sedangkan untuk menulis, setiap baris dengan semua kolomnya sepenuhnya ditulis ulang pada setiap UPDATE, tidak peduli kolom apa yang diubah. Jadi memiliki lebih banyak kolom jelas lebih mahal untuk menulis.
sumber
Jawaban Daniel berfokus pada biaya membaca setiap baris. Dalam konteks ini: Menempatkan
NOT NULL
kolom ukuran tetap terlebih dahulu di tabel Anda sedikit membantu. Menempatkan kolom yang relevan terlebih dahulu (yang Anda cari) sedikit membantu. Meminimalkan bantalan (karena penyelarasan data) dengan memainkan tetris penjajaran dengan kolom Anda dapat sedikit membantu. Tetapi efek yang paling penting belum disebutkan, terutama untuk tabel besar.Kolom tambahan jelas membuat baris menutupi lebih banyak ruang disk, sehingga baris yang lebih sedikit muat pada satu halaman data (8 kB secara default). Baris individual tersebar di lebih banyak halaman. Mesin basis data umumnya harus mengambil seluruh halaman, bukan baris individual . Tidak masalah apakah baris individu agak lebih kecil atau lebih besar - selama jumlah halaman yang sama harus dibaca.
Jika kueri mengambil sebagian kecil tabel besar, di mana baris tersebar kurang lebih secara acak di seluruh tabel, didukung oleh indeks, ini akan menghasilkan jumlah halaman yang dibaca kurang lebih sama, dengan sedikit perhatian ke ukuran baris. Kolom yang tidak relevan tidak akan banyak memperlambat Anda dalam kasus (jarang) seperti itu.
Biasanya, Anda akan mengambil tambalan atau kelompok baris yang telah dimasukkan secara berurutan atau kedekatan dan berbagi halaman data. Baris-baris itu tersebar karena kekacauan, lebih banyak halaman disk harus dibaca untuk memenuhi permintaan Anda. Harus membaca lebih banyak halaman biasanya merupakan alasan paling penting agar permintaan menjadi lebih lambat. Dan itu adalah faktor paling penting mengapa kolom yang tidak relevan membuat permintaan Anda lebih lambat.
Dengan basis data besar, biasanya tidak ada cukup RAM untuk menyimpan semuanya dalam memori cache. Baris yang lebih besar menempati lebih banyak cache, lebih banyak pertikaian, hit cache lebih sedikit, lebih banyak I / O disk. Dan membaca disk biasanya jauh lebih mahal. Kurang begitu dengan SSD, tetapi perbedaan besar tetap. Ini menambah poin di atas tentang membaca halaman.
Ini mungkin atau mungkin tidak masalah jika kolom tidak relevan yang TOAST-ed. Kolom yang relevan mungkin juga TOAST-ed, membawa kembali banyak efek yang sama.
sumber
Tes kecil:
Membatasi kueri ke 250 baris pertama (
WHERE num <= 250
) menghasilkan masing-masing 34,539 ms dan 8,343 ms. Memilih semua kecualilong_long_text
dari himpunan terbatas ini menghasilkan 18,432 ms. Ini menunjukkan bahwa dalam istilah Anda, PG cukup cerdas.sumber