Postgres GABUNG kondisi vs kondisi MANA

12

Pemula postgres di sini.

Saya ingin tahu apakah kueri ini dioptimalkan atau tidak? Saya mencoba untuk BERGABUNG PADA hanya nilai-nilai yang diperlukan 100% dan meninggalkan semua kondisi dinamis dalam klausa WHERE. Lihat di bawah.

SELECT *
    FROM
      myapp_employees
    JOIN myapp_users ON
      myapp_users.user_id=myapp_employees.user_id
    JOIN myapp_contacts_assoc ON
      myapp_contacts_assoc.user_id=myapp_users.user_id
    JOIN myapp_contacts ON
      myapp_contacts.contact_id=myapp_contacts_assoc.contact_id
    WHERE
      myapp_contacts.value='[email protected]' AND
      myapp_contacts.type=(1)::INT2 AND
      myapp_contacts.is_primary=(1)::INT2 AND
      myapp_contacts.expired_at IS NULL AND
      myapp_employees.status=(1)::INT2 AND
      myapp_users.status=(1)::INT2
    LIMIT 1;

Catatan: Untuk konteks, proc ini memeriksa untuk melihat apakah pengguna juga seorang karyawan (privs tinggi / tipe pengguna berbeda).

Ngomong-ngomong, apakah ini cara yang benar untuk pergi? Haruskah BERGABUNG DENGAN berisi lebih banyak pernyataan seperti memeriksa untuk expired_at IS NULL, misalnya? Mengapa atau mengapa ini tidak masuk akal?

Dan
sumber
Bagaimana dengan versi Postgres Anda? ( SELECT version();)
Erwin Brandstetter
@ ErwinBrandstetter Saya menjalankan PostgreSQL 9.3.14. Haruskah ini sesuatu yang saya butuhkan di setiap fungsi?
Dan
2
Tidak, kami di sini di dba.SE meminta Anda untuk mendeklarasikan versi perangkat lunak yang relevan, karena mereka membuat perbedaan untuk banyak pertanyaan.
Erwin Brandstetter

Jawaban:

14

Secara logis , tidak ada bedanya sama sekali apakah Anda menempatkan kondisi dalam klausa gabungan dari INNER JOINatau WHEREklausa yang sama SELECT. Efeknya sama.

(Bukan kasus untuk OUTER JOIN!)

Saat beroperasi dengan pengaturan default, itu juga tidak membuat perbedaan untuk rencana kueri atau kinerja . Postgres bebas mengatur ulang gabungan dan JOIN& WHEREkondisi dalam pencariannya untuk rencana kueri terbaik - selama jumlah tabel tidak lebih besar dari join_collapse_limit(default 8). Detail:

Untuk keterbacaan dan pemeliharaan , masuk akal untuk menempatkan kondisi yang menghubungkan tabel di masing-masing JOINklausa dan kondisi umum dalam WHEREklausa.

Permintaan Anda terlihat baik-baik saja. Saya akan menggunakan alias tabel untuk mengurangi kebisingan.

Detail kecil:

int2 '1'atau bahkan 1::int2lebih masuk akal daripada (1)::INT2. Dan sementara membandingkan dengan nilai tipe data numerik yang terdefinisi dengan baik, konstanta numerik biasa 1juga cukup baik.

Erwin Brandstetter
sumber
2

Beberapa poin ..

  1. Jika Anda bergabung dengan kondisi dengan nama yang sama ( user_id) dalam kasus Anda, Anda dapat menggunakan USING (user_id)daripada ON (a.user_id = b.user_id). Ini juga menyimpan kolom redundan yang berpotensi dikeluarkan (jika Anda menjalankan SELECT *produksi).

  2. 1::int2bermasalah. Baik status, dan is_primarydan lain-lain sudah int2dalam hal ini literal 1 akan secara otomatis dilemparkan ke int2, atau int2 dilemparkan ke int seperti pg yang cocok. Atau, jika Anda menyimpannya sebagai int reguler, dan membuangnya seolah-olah itu membuat perbedaan dalam perhitungan - yang tidak, para pemeran saja yang membuat proposisi yang hilang.

  3. Jika memungkinkan, semua :: int2 mungkin harus disimpan sebagai boolean. Maka Anda dapat menulis WHEREkondisi Anda menjadi lebih sederhana juga.

  4. Untuk jenis dan status Anda, Anda mungkin menginginkan suatu ENUMjenis.

Evan Carroll
sumber