Desain basis data untuk menangani 1 miliar baris dan penghitungan

10

Kami menerima data GPS waktu nyata dengan laju sekitar 5000 pr. menit (dari 4 server TCP). Setiap server menggunakan koneksi tunggal untuk memasukkan data, dan buffer data di antara sisipan. Setiap 15 menit atau lebih, sebuah layanan mengambil data ini, dan memprosesnya menjadi perjalanan. Setelah perjalanan telah dihasilkan, data GPS yang sebenarnya biasanya tidak begitu penting, hanya jika pengguna ingin melihat rute pada peta.

Masalahnya adalah bahwa tampaknya database sedang berjuang untuk mengikuti laju data yang dimasukkan. Kadang-kadang ketika beban meningkat, waktu memasukkan tiba-tiba meningkat secara drastis (> 30 detik), yang pada gilirannya memungkinkan lebih banyak data untuk disangga, yang pada gilirannya menghasilkan memasukkan yang lebih besar dan durasi memasukkan yang lebih lama.

Saya berharap mendapatkan komentar tentang desain saat ini, dan beberapa ide yang kami miliki untuk meningkatkan kinerja, dan menjawab beberapa pertanyaan kami - dan tips lain yang mungkin orang miliki!

Desain saat ini

Data saat ini dipisahkan menjadi tabel yang mewakili satu minggu, dan data yang lebih tua dari satu tahun diarsipkan ke dalam basis data sekunder. Semuanya digabungkan bersama dalam tampilan yang dapat diedit, yang digunakan untuk menyisipkan dan membaca.

Desain meja

  • Id (PK, pengenal unik)
  • DeviceId (FK, int)
  • PersonId (FK, int)
  • VehicleId (FK, int)
  • TokenId (FK, int)
  • UtcTime (PK, datetime2 (3))
  • Latitude (mengambang)
  • Bujur (mengambang)
  • Kecepatan (smallint)
  • Tajuk (smallint)
  • Satelit (tinyint)
  • IOData (varbinary (100))
  • IgnitionState (tinyint)
  • UserInput (tinyint)
  • CreateTimeUtc (datetime2 (3))

Indeks

  • DeviceId_CreateTimeUtc_Desc
  • DeviceId_UtcTime_Desc (Clustered)
  • PersonId_UtcTime_Desc
  • TokenId_UtcTime_Desc
  • VehicleId_UtcTime_Desc

Setiap minggu saat ini membutuhkan sekitar 10 GB termasuk indeks, dan saat ini ada sekitar 300 GB data di basis data utama.

Tabel data dalam database utama memiliki filegroup sendiri dengan 1 file, tetapi pada disk yang sama dengan semua tabel lainnya di database utama. Basis data sekunder ada di disk yang berbeda, tetapi di mesin yang sama.

Saya pikir kami juga menjalankan indeks membangun kembali pekerjaan setiap minggu, ketika partisi tabel baru (minggu) mulai digunakan. Tidak dilakukan penyusutan.

Mesin ini adalah HP 8-core dengan memori 12 GB, dan disk yang memegang basis data utama menjalankan RAID 10.

Ide ide

  • Batasi jumlah data yang disimpan dalam basis data primer hingga mis maksimal 1 bulan. Paling tidak itu akan membuat database lebih mudah dikelola untuk cadangan / restorasi, tetapi dapatkah kita mengharapkan peningkatan kinerja dengan melakukan ini?
  • Buat 2 file dalam filegroup untuk data saat ini, dan distribusikan ke 2 partisi fisik yang berbeda
  • Buat database master-slave yang menyimpan data saat ini, jadi memasukkan dan membaca dilakukan pada basis data yang berbeda
  • Letakkan file untuk data saat ini pada disk SSD (akankah mirroring membuat perbedaan kinerja dengan disk SSD?)

Harap beri tahu saya jika diperlukan lebih banyak info. Ada banyak sekali faktor yang memengaruhi kinerja, dan mungkin juga banyak cara untuk mengubahnya.

sondergard
sumber
Komentar bukan untuk diskusi panjang; percakapan ini telah dipindahkan ke obrolan .
Paul White 9

Jawaban:

8

5000 sisipan per menit adalah sekitar 83 sisipan per detik. Dengan 5 indeks, 400 baris fisik dimasukkan per detik. Jika beban kerja dalam memori ini tidak akan menimbulkan masalah bahkan untuk server terkecil. Bahkan jika ini adalah penyisipan baris demi baris menggunakan cara yang paling tidak efisien yang dapat saya pikirkan. 83 pertanyaan sepele per detik tidak menarik dari sudut pandang CPU.

Mungkin, Anda terikat disk. Anda dapat memverifikasi ini dengan melihat statistik menunggu atau STATISTICS IO.

Kueri Anda mungkin menyentuh banyak halaman berbeda sehingga kumpulan buffer tidak memiliki ruang untuk semuanya. Hal ini menyebabkan halaman sering dibaca dan mungkin juga penulisan disk acak.

Bayangkan sebuah tabel di mana Anda hanya memasukkan secara fisik di akhir karena kunci yang terus meningkat. Set kerja akan menjadi satu halaman: yang terakhir. Ini akan menghasilkan IO berurutan juga ketika penulis malas atau proses pos pemeriksaan menulis "akhir" dari tabel ke disk.

Bayangkan sebuah tabel dengan sisipan yang ditempatkan secara acak (contoh klasik: kunci panduan). Di sini, semua halaman adalah set kerja karena halaman acak akan disentuh untuk setiap sisipan. IO bersifat acak. Ini adalah kasus terburuk ketika datang ke set kerja.

Anda berada di tengah. Indeks Anda dari struktur (SomeValue, SequentialDateTime). Komponen pertama secara acak mengacak urutan yang disediakan oleh komponen kedua. Saya kira ada beberapa kemungkinan nilai untuk " SomeValue" sehingga Anda memiliki banyak titik sisipan yang ditempatkan secara acak di indeks Anda.

Anda mengatakan bahwa data dipecah menjadi tabel 10GB per minggu. Itu adalah titik awal yang baik karena set kerja sekarang dibatasi oleh 10GB (mengabaikan semua bacaan yang mungkin Anda lakukan). Dengan memori server 12GB, tidak mungkin semua halaman yang relevan dapat tetap tersimpan dalam memori.

Jika Anda dapat mengurangi ukuran "partisi" mingguan atau menambah sedikit memori server, Anda mungkin baik-baik saja.

Saya berharap bahwa memasukkan pada awal minggu lebih cepat dari pada akhir. Anda dapat menguji teori ini pada server dev dengan menjalankan benchmark dengan ukuran data tertentu dan secara bertahap mengurangi memori server hingga Anda melihat tangki kinerja.

Sekarang bahkan jika semua membaca dan menulis sesuai dengan memori Anda mungkin masih memiliki halaman kotor acak pembilasan IO. Satu-satunya cara untuk menghilangkan itu adalah dengan menulis ke posisi yang terletak bersama dalam indeks Anda. Jika Anda dapat mengkonversi indeks Anda untuk menggunakan kunci sekuensial (lebih) yang akan banyak membantu.

Sebagai solusi cepat saya akan menambahkan lapisan buffering antara klien dan tabel utama. Mungkin mengumpulkan 15 menit dari menulis ke meja pementasan dan secara berkala menyiramnya. Itu menghilangkan lonjakan beban dan menggunakan rencana yang lebih efisien untuk menulis ke meja besar.

usr
sumber
1
@ usr Terima kasih atas jawaban yang sangat komprehensif dan dijelaskan dengan baik! Kami sebenarnya telah membahas peningkatan memori server, tanpa mengetahui seberapa besar pengaruhnya - tetapi sekarang kami benar-benar memiliki alasan yang sangat kuat untuk melakukannya :) Anda benar bahwa "SomeValue" mengacak sebagian titik penyisipan secara acak - mungkin ada sekitar 10.000 id perangkat. Mengenai tabel pementasan, apakah saran Anda sebuah tabel tanpa indeks, dan kemudian pekerjaan untuk dimasukkan ke dalam tabel utama setiap X menit?
sondergard
@ usr Reg. saran Anda untuk mengonversi indeks yang dikelompokkan menjadi berurutan, kami dapat menambahkan auto-inc. kolom identitas (integer), dan ubah indeks berkerumun ke kolom ini dengan tujuan semata-mata menjaganya tetap berurutan? Itu tidak akan unik di seluruh tabel, tetapi selama kunci primernya, kita harus baik-baik saja.
sondergard
1
Jika tabel pementasan kecil dan kueri Anda dapat hidup dengan itu maka Anda tidak perlu mengindeks sama sekali. Tetapi Anda bisa .; Salah satu strategi adalah membuat CI pada kolom identitas (seperti yang Anda katakan). Ini dapat bekerja dengan baik jika CI besar dan indeks lainnya kecil. Karena CI sedang menulis sekarang berurutan mereka memberikan kontribusi jauh lebih sedikit untuk masalah Anda. Strategi ini paling berhasil jika ada perbedaan ukuran yang bermakna .; Gagasan lain adalah memiliki satu meja per hari. Mungkin menggabungkan bulanan.
usr
Ok jadi kami melihat ke dalam membuat kolom identitas untuk CI, tapi sayangnya itu tidak mungkin pada tampilan yang dipisah-pisahkan (tidak ada kolom identitas yang diizinkan, tidak ada nilai default dan semua kolom harus dimasukkan dalam sisipan). Mungkin tampilan partioned adalah desain yang dipilih dengan buruk, meskipun direkomendasikan oleh konsultan
sondergard
2
Serius, bagi siapa pun yang menghadapi masalah yang sama, jika Anda punya banyak tulisan dan hanya sedikit yang membaca, Anda benar-benar ingin menambahkan di akhir dan menunda pengindeksan. Di sisi lain, jika Anda ingin membaca cepat dan tidak peduli berapa lama untuk memasukkan Anda perlu indeks berkerumun.
tiktak