Bagaimana Kolum Tanpa Indeks Melumpuhkan Pangkalan Data Kami

Satu indeks yang hilang menukarkan API 8 ms kepada mimpi ngeri 8 saat.

Kami menjalankan ujian beban sebelum pelancaran besar. Pembangunan lokal berjalan lancar dengan 100 rekod. Kemudian, kami mensimulasikan 500 pengguna terhadap 1.5 juta baris dalam data bersaiz pengeluaran (production).

Keputusannya sangat buruk:

  • Masa tindak balas API melonjak dari 45 ms ke 8,000 ms.
  • CPU Pangkalan Data mencecah 100 %.
  • Kolam sambungan (connection pools) habis digunakan, menyebabkan ralat tamat masa (timeout).

Kami menyemak log pertanyaan perlahan (slow-query log) dan menemui satu endpoint yang mengambil sejarah pesanan berdasarkan ID pengguna dan status.

Menjalankan EXPLAIN ANALYZE pada PostgreSQL menunjukkan imbasan berurutan (Sequential Scan). Enjin membaca kesemua 1.5 juta baris bagi setiap permintaan kerana tiada indeks pada user_id.

Dengan 100 permintaan serentak, ia mengimbas 150 juta baris sekaligus.

Penyelesaiannya hanya mengambil masa lima minit.

Daripada sekadar menggunakan indeks ringkas pada user_id, kami mencipta indeks komposit pada (user_id, status, created_at DESC). Ini membolehkan pangkalan data:

  • Menapis mengikut user_id.
  • Menapis mengikut status.
  • Mengembalikan baris terbaru dengan serta-merta.
  • Melangkau langkah penyusunan tambahan.

Kami menggunakan CREATE INDEX CONCURRENTLY supaya jadual kekal tidak berkunci semasa operasi dijalankan.

Selepas pembaikan:

  • Masa pertanyaan jatuh dari 8,150 ms ke 0.14 ms.
  • Latensi API menurun dari 8 saat ke 12 ms.
  • Penggunaan CPU merosot dari 100 % ke bawah 8 %.

Pengajaran yang diperoleh:

  • Ujian lokal boleh mengelirukan; 100 baris tidak mewakili satu juta.
  • Indekskan kunci asing (foreign keys) anda—kebanyakan ORM mengabaikan perkara ini.
  • Jalankan EXPLAIN ANALYZE sebelum membeli perkakasan tambahan.
  • Reka indeks berdasarkan pertanyaan yang anda jalankan secara nyata.

Jangan skala pelayan dahulu. Skalakan pertanyaan anda.

Sumber: https://dev.to/mia_keller_ffd2584c046ecb/how-an-unindexed-column-silently-killed-our-database-under-load-and-the-5-minute-fix-m32