Mengoptimalkan SQLite itu rumit. Kinerja penyisipan massal aplikasi C dapat bervariasi dari 85 sisipan per detik hingga lebih dari 96.000 sisipan per detik!
Latar Belakang: Kami menggunakan SQLite sebagai bagian dari aplikasi desktop. Kami memiliki sejumlah besar data konfigurasi yang disimpan dalam file XML yang diuraikan dan dimuat ke dalam database SQLite untuk diproses lebih lanjut ketika aplikasi diinisialisasi. SQLite sangat ideal untuk situasi ini karena cepat, tidak memerlukan konfigurasi khusus, dan database disimpan dalam disk sebagai file tunggal.
Dasar Pemikiran: Awalnya saya kecewa dengan kinerja yang saya lihat. Ternyata kinerja SQLite dapat sangat bervariasi (baik untuk memasukkan massal dan memilih) tergantung pada bagaimana database dikonfigurasikan dan bagaimana Anda menggunakan API. Itu bukan masalah sepele untuk mencari tahu apa semua opsi dan teknik itu, jadi saya pikir itu bijaksana untuk membuat entri wiki komunitas ini untuk berbagi hasil dengan pembaca Stack Overflow untuk menyelamatkan orang lain dari masalah penyelidikan yang sama.
Eksperimen: Daripada hanya berbicara tentang tips kinerja dalam pengertian umum (yaitu "Gunakan transaksi!" ), Saya pikir yang terbaik adalah menulis beberapa kode C dan benar - benar mengukur dampak dari berbagai opsi. Kita akan mulai dengan beberapa data sederhana:
- File teks dibatasi TAB 28 MB (sekitar 865.000 catatan) dari jadwal transit lengkap untuk kota Toronto
- Mesin uji saya adalah P60 3,60 GHz yang menjalankan Windows XP.
- Kode ini dikompilasi dengan Visual C ++ 2005 sebagai "Release" dengan "Full Optimization" (/ Ox) dan Favor Fast Code (/ Ot).
- Saya menggunakan SQLite "Amalgamation", dikompilasi langsung ke aplikasi pengujian saya. Versi SQLite yang kebetulan saya miliki sedikit lebih tua (3.6.7), tetapi saya menduga hasil ini akan sebanding dengan rilis terbaru (silakan tinggalkan komentar jika Anda berpikir sebaliknya).
Mari kita menulis beberapa kode!
Kode: Program C sederhana yang membaca file teks baris demi baris, membagi string menjadi nilai-nilai dan kemudian memasukkan data ke dalam database SQLite. Dalam versi kode "baseline" ini, database dibuat, tetapi kami tidak akan benar-benar memasukkan data:
/*************************************************************
Baseline code to experiment with SQLite performance.
Input data is a 28 MB TAB-delimited text file of the
complete Toronto Transit System schedule/route info
from http://www.toronto.ca/open/datasets/ttc-routes/
**************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include "sqlite3.h"
#define INPUTDATA "C:\\TTC_schedule_scheduleitem_10-27-2009.txt"
#define DATABASE "c:\\TTC_schedule_scheduleitem_10-27-2009.sqlite"
#define TABLE "CREATE TABLE IF NOT EXISTS TTC (id INTEGER PRIMARY KEY, Route_ID TEXT, Branch_Code TEXT, Version INTEGER, Stop INTEGER, Vehicle_Index INTEGER, Day Integer, Time TEXT)"
#define BUFFER_SIZE 256
int main(int argc, char **argv) {
sqlite3 * db;
sqlite3_stmt * stmt;
char * sErrMsg = 0;
char * tail = 0;
int nRetCode;
int n = 0;
clock_t cStartClock;
FILE * pFile;
char sInputBuf [BUFFER_SIZE] = "\0";
char * sRT = 0; /* Route */
char * sBR = 0; /* Branch */
char * sVR = 0; /* Version */
char * sST = 0; /* Stop Number */
char * sVI = 0; /* Vehicle */
char * sDT = 0; /* Date */
char * sTM = 0; /* Time */
char sSQL [BUFFER_SIZE] = "\0";
/*********************************************/
/* Open the Database and create the Schema */
sqlite3_open(DATABASE, &db);
sqlite3_exec(db, TABLE, NULL, NULL, &sErrMsg);
/*********************************************/
/* Open input file and import into Database*/
cStartClock = clock();
pFile = fopen (INPUTDATA,"r");
while (!feof(pFile)) {
fgets (sInputBuf, BUFFER_SIZE, pFile);
sRT = strtok (sInputBuf, "\t"); /* Get Route */
sBR = strtok (NULL, "\t"); /* Get Branch */
sVR = strtok (NULL, "\t"); /* Get Version */
sST = strtok (NULL, "\t"); /* Get Stop Number */
sVI = strtok (NULL, "\t"); /* Get Vehicle */
sDT = strtok (NULL, "\t"); /* Get Date */
sTM = strtok (NULL, "\t"); /* Get Time */
/* ACTUAL INSERT WILL GO HERE */
n++;
}
fclose (pFile);
printf("Imported %d records in %4.2f seconds\n", n, (clock() - cStartClock) / (double)CLOCKS_PER_SEC);
sqlite3_close(db);
return 0;
}
Kontrol"
Menjalankan kode apa adanya tidak benar-benar melakukan operasi basis data apa pun, tetapi akan memberi kita gambaran tentang seberapa cepat I / O file C mentah dan operasi pemrosesan string.
Mengimpor 864913 catatan dalam 0,94 detik
Bagus! Kita dapat melakukan 920.000 sisipan per detik, asalkan kita tidak benar-benar melakukan sisipan :-)
"Skenario Kasus Terburuk"
Kita akan membuat string SQL menggunakan nilai yang dibaca dari file dan memanggil operasi SQL menggunakan sqlite3_exec:
sprintf(sSQL, "INSERT INTO TTC VALUES (NULL, '%s', '%s', '%s', '%s', '%s', '%s', '%s')", sRT, sBR, sVR, sST, sVI, sDT, sTM);
sqlite3_exec(db, sSQL, NULL, NULL, &sErrMsg);
Ini akan menjadi lambat karena SQL akan dikompilasi ke dalam kode VDBE untuk setiap sisipan dan setiap sisipan akan terjadi dalam transaksi sendiri. Seberapa lambat?
Impor 864913 catatan dalam 9933,61 detik
Astaga! 2 jam dan 45 menit! Itu hanya 85 sisipan per detik.
Menggunakan Transaksi
Secara default, SQLite akan mengevaluasi setiap pernyataan INSERT / UPDATE dalam transaksi unik. Jika melakukan banyak menyisipkan, disarankan untuk membungkus operasi Anda dalam suatu transaksi:
sqlite3_exec(db, "BEGIN TRANSACTION", NULL, NULL, &sErrMsg);
pFile = fopen (INPUTDATA,"r");
while (!feof(pFile)) {
...
}
fclose (pFile);
sqlite3_exec(db, "END TRANSACTION", NULL, NULL, &sErrMsg);
Impor 864913 catatan dalam 38,03 detik
Itu lebih baik. Cukup dengan membungkus semua sisipan kami dalam satu transaksi meningkatkan kinerja kami menjadi 23.000 sisipan per detik.
Menggunakan Pernyataan Disiapkan
Menggunakan transaksi adalah peningkatan besar, tetapi mengkompilasi ulang pernyataan SQL untuk setiap sisipan tidak masuk akal jika kita menggunakan SQL yang sama berulang-ulang. Mari kita gunakan sqlite3_prepare_v2
untuk mengkompilasi pernyataan SQL kita sekali dan kemudian ikat parameter kita ke pernyataan itu menggunakan sqlite3_bind_text
:
/* Open input file and import into the database */
cStartClock = clock();
sprintf(sSQL, "INSERT INTO TTC VALUES (NULL, @RT, @BR, @VR, @ST, @VI, @DT, @TM)");
sqlite3_prepare_v2(db, sSQL, BUFFER_SIZE, &stmt, &tail);
sqlite3_exec(db, "BEGIN TRANSACTION", NULL, NULL, &sErrMsg);
pFile = fopen (INPUTDATA,"r");
while (!feof(pFile)) {
fgets (sInputBuf, BUFFER_SIZE, pFile);
sRT = strtok (sInputBuf, "\t"); /* Get Route */
sBR = strtok (NULL, "\t"); /* Get Branch */
sVR = strtok (NULL, "\t"); /* Get Version */
sST = strtok (NULL, "\t"); /* Get Stop Number */
sVI = strtok (NULL, "\t"); /* Get Vehicle */
sDT = strtok (NULL, "\t"); /* Get Date */
sTM = strtok (NULL, "\t"); /* Get Time */
sqlite3_bind_text(stmt, 1, sRT, -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 2, sBR, -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 3, sVR, -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 4, sST, -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 5, sVI, -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 6, sDT, -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 7, sTM, -1, SQLITE_TRANSIENT);
sqlite3_step(stmt);
sqlite3_clear_bindings(stmt);
sqlite3_reset(stmt);
n++;
}
fclose (pFile);
sqlite3_exec(db, "END TRANSACTION", NULL, NULL, &sErrMsg);
printf("Imported %d records in %4.2f seconds\n", n, (clock() - cStartClock) / (double)CLOCKS_PER_SEC);
sqlite3_finalize(stmt);
sqlite3_close(db);
return 0;
Mengimpor 864913 catatan dalam 16,27 detik
Bagus! Ada sedikit lebih banyak kode (jangan lupa untuk menelepon sqlite3_clear_bindings
dan sqlite3_reset
), tetapi kami telah lebih dari dua kali lipat kinerja kami menjadi 53.000 sisipan per detik.
PRAGMA sinkron = MATI
Secara default, SQLite akan berhenti setelah mengeluarkan perintah tulis tingkat OS. Ini menjamin bahwa data ditulis ke disk. Dengan menetapkan synchronous = OFF
, kami menginstruksikan SQLite untuk menyerahkan data ke OS untuk ditulis dan kemudian melanjutkan. Ada kemungkinan file database menjadi rusak jika komputer mengalami kerusakan (atau kegagalan daya) bencana sebelum data dituliskan ke piring:
/* Open the database and create the schema */
sqlite3_open(DATABASE, &db);
sqlite3_exec(db, TABLE, NULL, NULL, &sErrMsg);
sqlite3_exec(db, "PRAGMA synchronous = OFF", NULL, NULL, &sErrMsg);
Mengimpor 864913 catatan dalam 12,41 detik
Peningkatannya sekarang lebih kecil, tapi kami mencapai 69.600 sisipan per detik.
PRAGMA journal_mode = MEMORY
Pertimbangkan menyimpan jurnal rollback dalam memori dengan mengevaluasi PRAGMA journal_mode = MEMORY
. Transaksi Anda akan lebih cepat, tetapi jika Anda kehilangan daya atau program Anda macet selama transaksi, basis data Anda bisa dibiarkan dalam keadaan korup dengan transaksi yang diselesaikan sebagian:
/* Open the database and create the schema */
sqlite3_open(DATABASE, &db);
sqlite3_exec(db, TABLE, NULL, NULL, &sErrMsg);
sqlite3_exec(db, "PRAGMA journal_mode = MEMORY", NULL, NULL, &sErrMsg);
Impor 864913 catatan dalam 13,50 detik
Sedikit lebih lambat dari optimasi sebelumnya di 64.000 sisipan per detik.
PRAGMA sinkron = MATI dan PRAGMA journal_mode = MEMORY
Mari kita gabungkan dua optimasi sebelumnya. Ini sedikit lebih berisiko (jika terjadi kerusakan), tetapi kami hanya mengimpor data (tidak menjalankan bank):
/* Open the database and create the schema */
sqlite3_open(DATABASE, &db);
sqlite3_exec(db, TABLE, NULL, NULL, &sErrMsg);
sqlite3_exec(db, "PRAGMA synchronous = OFF", NULL, NULL, &sErrMsg);
sqlite3_exec(db, "PRAGMA journal_mode = MEMORY", NULL, NULL, &sErrMsg);
Mengimpor 864913 catatan dalam 12,00 detik
Fantastis! Kami dapat melakukan 72.000 sisipan per detik.
Menggunakan Database Dalam Memori
Hanya untuk iseng, mari kita membangun semua optimasi sebelumnya dan mendefinisikan kembali nama database sehingga kami bekerja sepenuhnya dalam RAM:
#define DATABASE ":memory:"
Mengimpor 864913 catatan dalam 10,94 detik
Tidak super praktis untuk menyimpan basis data kami dalam RAM, tetapi mengesankan bahwa kami dapat melakukan 79.000 sisipan per detik.
Refactoring Kode C
Meskipun tidak secara khusus peningkatan SQLite, saya tidak suka char*
operasi penugasan ekstra di while
loop. Mari kita cepat-cepat memperbaiki kode itu untuk meneruskan output strtok()
langsung ke sqlite3_bind_text()
, dan biarkan kompiler mencoba mempercepatnya untuk kita:
pFile = fopen (INPUTDATA,"r");
while (!feof(pFile)) {
fgets (sInputBuf, BUFFER_SIZE, pFile);
sqlite3_bind_text(stmt, 1, strtok (sInputBuf, "\t"), -1, SQLITE_TRANSIENT); /* Get Route */
sqlite3_bind_text(stmt, 2, strtok (NULL, "\t"), -1, SQLITE_TRANSIENT); /* Get Branch */
sqlite3_bind_text(stmt, 3, strtok (NULL, "\t"), -1, SQLITE_TRANSIENT); /* Get Version */
sqlite3_bind_text(stmt, 4, strtok (NULL, "\t"), -1, SQLITE_TRANSIENT); /* Get Stop Number */
sqlite3_bind_text(stmt, 5, strtok (NULL, "\t"), -1, SQLITE_TRANSIENT); /* Get Vehicle */
sqlite3_bind_text(stmt, 6, strtok (NULL, "\t"), -1, SQLITE_TRANSIENT); /* Get Date */
sqlite3_bind_text(stmt, 7, strtok (NULL, "\t"), -1, SQLITE_TRANSIENT); /* Get Time */
sqlite3_step(stmt); /* Execute the SQL Statement */
sqlite3_clear_bindings(stmt); /* Clear bindings */
sqlite3_reset(stmt); /* Reset VDBE */
n++;
}
fclose (pFile);
Catatan: Kami kembali menggunakan file database nyata. Database dalam memori cepat, tetapi belum tentu praktis
Mengimpor 864913 catatan dalam 8,94 detik
Sedikit refactoring ke kode pemrosesan string yang digunakan dalam pengikatan parameter kami telah memungkinkan kami untuk melakukan 96.700 sisipan per detik. Saya pikir aman untuk mengatakan bahwa ini sangat cepat . Ketika kita mulai mengubah variabel lain (yaitu ukuran halaman, pembuatan indeks, dll.) Ini akan menjadi patokan kami.
Ringkasan (sejauh ini)
Saya harap Anda masih bersama saya! Alasan kami memulai jalan ini adalah karena kinerja penyisipan massal sangat bervariasi dengan SQLite, dan tidak selalu jelas perubahan apa yang perlu dilakukan untuk mempercepat operasi kami. Menggunakan kompiler yang sama (dan opsi kompiler), versi SQLite yang sama dan data yang sama kami telah mengoptimalkan kode kami dan penggunaan SQLite kami untuk beralih dari skenario terburuk dari 85 sisipan per detik menjadi lebih dari 96.000 sisipan per detik!
BUAT INDEX lalu INSERT vs. INSERT lalu BUAT INDEX
Sebelum kita mulai mengukur SELECT
kinerja, kita tahu bahwa kita akan membuat indeks. Diusulkan dalam salah satu jawaban di bawah ini bahwa ketika melakukan penyisipan massal, lebih cepat membuat indeks setelah data dimasukkan (sebagai lawan membuat indeks terlebih dahulu kemudian memasukkan data). Mari mencoba:
Buat Indeks lalu Sisipkan Data
sqlite3_exec(db, "CREATE INDEX 'TTC_Stop_Index' ON 'TTC' ('Stop')", NULL, NULL, &sErrMsg);
sqlite3_exec(db, "BEGIN TRANSACTION", NULL, NULL, &sErrMsg);
...
Mengimpor 864913 catatan dalam 18,13 detik
Masukkan Data, lalu Buat Indeks
...
sqlite3_exec(db, "END TRANSACTION", NULL, NULL, &sErrMsg);
sqlite3_exec(db, "CREATE INDEX 'TTC_Stop_Index' ON 'TTC' ('Stop')", NULL, NULL, &sErrMsg);
Mengimpor 864913 catatan dalam 13,66 detik
Seperti yang diharapkan, sisipan massal lebih lambat jika satu kolom diindeks, tetapi itu membuat perbedaan jika indeks dibuat setelah data dimasukkan. Baseline tanpa indeks kami adalah 96.000 sisipan per detik. Membuat indeks terlebih dahulu kemudian memasukkan data memberi kita 47.700 sisipan per detik, sedangkan memasukkan data terlebih dahulu kemudian membuat indeks memberi kita 63.300 sisipan per detik.
Dengan senang hati saya akan mengambil saran untuk skenario lain untuk dicoba ... Dan akan segera mengkompilasi data serupa untuk pertanyaan SELECT.
sumber
sqlite3_clear_bindings(stmt);
? Anda menyetel binding setiap kali harus cukup: Sebelum memanggil sqlite3_step () untuk pertama kali atau segera setelah sqlite3_reset (), aplikasi dapat memanggil salah satu antarmuka sqlite3_bind () untuk melampirkan nilai pada parameter. Setiap panggilan ke sqlite3_bind () mengabaikan bindings sebelumnya pada parameter yang sama (lihat: sqlite.org/cintro.html ). Tidak ada dalam dokumen untuk fungsi yang mengatakan Anda harus memanggilnya.feof()
untuk mengontrol penghentian loop input Anda. Gunakan hasil yang dikembalikan olehfgets()
. stackoverflow.com/a/15485689/827263Jawaban:
Beberapa tips:
pragma journal_mode
). AdaNORMAL
, dan kemudian adaOFF
, yang secara signifikan dapat meningkatkan kecepatan memasukkan jika Anda tidak terlalu khawatir tentang database yang mungkin rusak jika OS lumpuh. Jika aplikasi Anda macet, data harusnya baik-baik saja. Perhatikan bahwa dalam versi yang lebih baru,OFF/MEMORY
pengaturan tidak aman untuk tingkat aplikasi crash.PRAGMA page_size
). Memiliki ukuran halaman yang lebih besar dapat membuat membaca dan menulis berjalan sedikit lebih cepat karena halaman yang lebih besar disimpan dalam memori. Perhatikan bahwa lebih banyak memori akan digunakan untuk basis data Anda.CREATE INDEX
setelah melakukan semua sisipan Anda. Ini secara signifikan lebih cepat daripada membuat indeks dan kemudian melakukan sisipan Anda.INTEGER PRIMARY KEY
jika mungkin, yang akan menggantikan kolom nomor baris unik yang tersirat dalam tabel.!feof(file)
!Saya juga mengajukan pertanyaan serupa di sini dan di sini .
sumber
Coba gunakan
SQLITE_STATIC
alih-alihSQLITE_TRANSIENT
untuk sisipan tersebut.SQLITE_TRANSIENT
akan menyebabkan SQLite menyalin data string sebelum kembali.SQLITE_STATIC
memberitahu itu bahwa alamat memori yang Anda berikan akan valid sampai permintaan dilakukan (yang dalam loop ini selalu demikian). Ini akan menghemat beberapa operasi alokasi, salin, dan alokasikan semua per loop. Mungkin perbaikan besar.sumber
Hindari
sqlite3_clear_bindings(stmt)
.Kode dalam tes ini mengatur binding setiap kali harus cukup.
The C API intro dari docs SQLite mengatakan:
Tidak ada dalam dokumen untuk
sqlite3_clear_bindings
mengatakan Anda harus memanggilnya selain hanya mengatur binding.Lebih detail: Avoid_sqlite3_clear_bindings ()
sumber
Pada sisipan massal
Terinspirasi oleh posting ini dan oleh pertanyaan Stack Overflow yang membawa saya ke sini - Apakah mungkin untuk memasukkan beberapa baris sekaligus dalam database SQLite? - Saya telah memposting repositori Git pertama saya :
https://github.com/rdpoor/CreateOrUpdateyang memuat banyak array ActiveRecords ke dalam database MySQL , SQLite atau PostgreSQL . Ini termasuk opsi untuk mengabaikan catatan yang ada, menimpa mereka atau meningkatkan kesalahan. Tolok ukur dasar saya menunjukkan peningkatan kecepatan 10x dibandingkan dengan penulisan berurutan - YMMV.
Saya menggunakannya dalam kode produksi di mana saya sering perlu mengimpor dataset besar, dan saya cukup senang dengannya.
sumber
Impor massal tampaknya berkinerja terbaik jika Anda dapat memotong pernyataan INSERT / UPDATE Anda . Nilai 10.000 atau lebih telah bekerja dengan baik untuk saya di atas meja dengan hanya beberapa baris, YMMV ...
sumber
Jika Anda hanya peduli tentang membaca, versi yang agak lebih cepat (tetapi mungkin membaca data basi) adalah membaca dari beberapa koneksi dari beberapa utas (koneksi per-utas).
Pertama-tama temukan item, dalam tabel:
lalu baca di halaman (LIMIT / OFFSET):
di mana dan dihitung per-utas, seperti ini:
untuk setiap utas:
Untuk db (200mb) kecil kami, ini membuat kecepatan 50-75% (3.8.0.2 64-bit pada Windows 7). Tabel kami sangat non-normal (1000-1500 kolom, sekitar 100.000 atau lebih baris).
Terlalu banyak atau terlalu sedikit utas tidak akan melakukannya, Anda perlu membuat tolok ukur dan profil sendiri.
Juga bagi kami, SHAREDCACHE membuat kinerja lebih lambat, jadi saya menempatkan PRIVATECACHE secara manual (karena itu diaktifkan secara global untuk kami)
sumber
Saya tidak bisa mendapatkan keuntungan dari transaksi sampai saya menaikkan cache_size ke nilai yang lebih tinggi yaitu
PRAGMA cache_size=10000;
sumber
cache_size
menetapkan jumlah halaman yang akan di-cache , bukan ukuran total RAM. Dengan ukuran halaman default 4kB, pengaturan ini akan menampung hingga 40MB data per file terbuka (atau per proses, jika berjalan dengan cache bersama ).Setelah membaca tutorial ini, saya mencoba mengimplementasikannya ke program saya.
Saya punya 4-5 file yang berisi alamat. Setiap file memiliki sekitar 30 juta catatan. Saya menggunakan konfigurasi yang sama dengan yang Anda sarankan, tetapi jumlah INSERT saya per detiknya sangat rendah (~ 10.000 catatan per detik).
Di sinilah saran Anda gagal. Anda menggunakan satu transaksi untuk semua catatan dan satu sisipan tanpa kesalahan / gagal. Katakanlah Anda membagi setiap rekaman menjadi beberapa sisipan pada tabel yang berbeda. Apa yang terjadi jika catatan rusak?
Perintah ON CONFLICT tidak berlaku, karena jika Anda memiliki 10 elemen dalam catatan dan Anda perlu setiap elemen dimasukkan ke tabel yang berbeda, jika elemen 5 mendapatkan kesalahan CONSTRAINT, maka semua 4 sisipan sebelumnya harus pergi juga.
Jadi di sinilah kemunduran datang. Satu-satunya masalah dengan rollback adalah Anda kehilangan semua sisipan dan mulai dari atas. Bagaimana Anda bisa menyelesaikan ini?
Solusi saya adalah menggunakan beberapa transaksi. Saya memulai dan mengakhiri transaksi setiap 10.000 catatan (Jangan tanya mengapa angka itu, itu yang tercepat yang saya uji). Saya membuat array berukuran 10.000 dan menyisipkan catatan yang berhasil di sana. Ketika kesalahan terjadi, saya melakukan rollback, memulai transaksi, memasukkan catatan dari array saya, melakukan dan kemudian memulai transaksi baru setelah catatan rusak.
Solusi ini membantu saya melewati masalah yang saya miliki ketika berhadapan dengan file yang berisi catatan buruk / duplikat (saya memiliki hampir 4% catatan buruk).
Algoritma yang saya buat membantu saya mengurangi proses saya hingga 2 jam. Proses pemuatan akhir dari file 1 jam 30 m yang masih lambat tetapi tidak dibandingkan dengan 4 jam yang awalnya diperlukan. Saya berhasil mempercepat insert dari 10.000 / s menjadi ~ 14.000 / s
Jika ada yang punya ide lain tentang cara mempercepatnya, saya terbuka untuk saran.
PEMBARUAN :
Selain jawaban saya di atas, Anda harus ingat bahwa memasukkan per detik tergantung pada hard drive yang Anda gunakan juga. Saya mengujinya pada 3 PC yang berbeda dengan hard drive yang berbeda dan mendapat perbedaan besar dalam waktu. PC1 (1 jam 30m), PC2 (6 jam) PC3 (14 jam), jadi saya mulai bertanya-tanya mengapa itu terjadi.
Setelah dua minggu meneliti dan memeriksa berbagai sumber daya: Hard Drive, Ram, Cache, saya mengetahui bahwa beberapa pengaturan pada hard drive Anda dapat memengaruhi tingkat I / O. Dengan mengklik properti pada drive output yang Anda inginkan, Anda dapat melihat dua opsi di tab umum. Opt1: Kompres drive ini, Opt2: Izinkan file drive ini memiliki konten yang diindeks.
Dengan menonaktifkan kedua opsi ini, ketiga PC sekarang membutuhkan waktu yang hampir bersamaan untuk menyelesaikan (1 jam dan 20 hingga 40 menit). Jika Anda menemukan sisipan lambat, periksa apakah hard drive Anda dikonfigurasi dengan opsi ini. Ini akan menghemat banyak waktu dan sakit kepala saat mencoba menemukan solusinya
sumber
Jawaban atas pertanyaan Anda adalah bahwa SQLite 3 yang lebih baru telah meningkatkan kinerja, gunakan itu.
Jawaban ini Mengapa SQLAlchemy memasukkan dengan sqlite 25 kali lebih lambat daripada menggunakan sqlite3 secara langsung? oleh SqlAlchemy Orm Penulis memiliki 100k sisipan dalam 0,5 detik, dan saya telah melihat hasil yang serupa dengan python-sqlite dan SqlAlchemy. Yang membuat saya percaya bahwa kinerja telah meningkat dengan SQLite 3.
sumber
Gunakan ContentProvider untuk memasukkan data massal dalam db. Metode di bawah ini digunakan untuk memasukkan data massal ke dalam basis data. Ini harus meningkatkan kinerja SQLite INSERT-per-detik.
Hubungi metode bulkInsert:
Tautan: https://www.vogella.com/tutorials/AndroidSQLite/article.html periksa Menggunakan Bagian ContentProvider untuk lebih jelasnya
sumber