PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Mengoptimalkan banyak gabungan

Selalu ada 2 hal yang perlu dipertimbangkan saat mengoptimalkan kueri:

  • Indeks apa yang dapat digunakan (Anda mungkin perlu membuat indeks)
  • Bagaimana kueri ditulis (Anda mungkin perlu mengubah kueri agar pengoptimal kueri dapat menemukan indeks yang sesuai, dan tidak membaca ulang data secara berlebihan)

Beberapa pengamatan:

  • Anda melakukan manipulasi tanggal sebelum bergabung dengan teman kencan Anda. Sebagai aturan umum, ini akan mencegah pengoptimal kueri menggunakan indeks meskipun indeks itu ada. Anda harus mencoba untuk menulis ekspresi Anda sedemikian rupa sehingga kolom yang diindeks tidak berubah di satu sisi ekspresi.

  • Subkueri Anda difilter ke rentang tanggal yang sama dengan generate_series . Ini adalah duplikasi, dan membatasi kemampuan pengoptimal untuk memilih pengoptimalan yang paling efisien. Saya menduga itu mungkin ditulis untuk meningkatkan kinerja karena pengoptimal tidak dapat menggunakan indeks pada kolom tanggal (body_time )?

  • CATATAN :Kami sebenarnya sangat ingin menggunakan indeks pada Body.body_time

  • ORDER BY dalam subqueries paling-paling berlebihan. Paling buruk itu bisa memaksa pengoptimal kueri untuk mengurutkan hasil yang ditetapkan sebelum bergabung; dan itu belum tentu bagus untuk rencana kueri. Alih-alih hanya menerapkan pemesanan tepat di akhir untuk tampilan akhir.

  • Penggunaan LEFT JOIN di subkueri Anda tidak pantas. Dengan asumsi Anda menggunakan konvensi ANSI untuk NULL perilaku (dan Anda seharusnya), luar bergabung ke envelope akan mengembalikan envelope_command=NULL , dan ini akibatnya akan dikecualikan oleh kondisi envelope_command=? .

  • Subkueri o dan i hampir identik kecuali untuk envelope_command nilai. Ini memaksa pengoptimal untuk memindai tabel dasar yang sama dua kali. Anda dapat menggunakan tabel pivot teknik untuk menggabungkan data satu kali, dan membagi nilai menjadi 2 kolom.

Coba yang berikut ini yang menggunakan teknik pivot:

SELECT  p.period,
        /*The pivot technique in action...*/
        SUM(
        CASE WHEN envelope_command = 1 THEN body_size
        ELSE 0
        END) AS Outbound,
        SUM(
        CASE WHEN envelope_command = 2 THEN body_size
        ELSE 0
        END) AS Inbound
FROM    (
        SELECT  date '2009-10-01' + s.day AS period
        FROM    generate_series(0, date '2009-10-31' - date '2009-10-01') AS s(day)
        ) AS p 
        /*The left JOIN is justified to ensure ALL generated dates are returned
          Also: it joins to a subquery, else the JOIN to envelope _could_ exclude some generated dates*/
        LEFT OUTER JOIN (
        SELECT  b.body_size,
                b.body_time,
                e.envelope_command
        FROM    body AS b 
                INNER JOIN envelope e 
                  ON e.message_id = b.message_id 
        WHERE   envelope_command IN (1, 2)
        ) d
          /*The expressions below allow the optimser to use an index on body_time if 
            the statistics indicate it would be beneficial*/
          ON d.body_time >= p.period
         AND d.body_time < p.period + INTERVAL '1 DAY'
GROUP BY p.Period
ORDER BY p.Period

EDIT :Menambahkan filter yang disarankan oleh Tom H.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. ProtocolViolation:ERROR:pesan ikat memasok 0 parameter, tetapi pernyataan yang disiapkan membutuhkan 1

  2. NodeJS/Knex Membuat Respons Json

  3. Bagaimana cara membuat urutan partisi PostgreSQL?

  4. Mungkinkah melakukan kueri lintas basis data dengan PostgreSQL?

  5. Operator Bitwise PostgreSQL dengan variasi bit tidak dapat DAN string bit dengan ukuran berbeda