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.
sumber
Jawaban:
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.
sumber