Android menawarkan dukungan bawaan untuk SQLite, database SQL yang efisien. Ikuti praktik terbaik ini untuk mengoptimalkan performa aplikasi Anda, memastikannya tetap cepat dan dapat diprediksi dengan cepat seiring pertumbuhan data Anda. Dengan menggunakan praktik terbaik ini, Anda juga mengurangi kemungkinan terjadinya masalah performa yang sulit direproduksi dan dipecahkan.
Untuk mencapai performa yang lebih cepat, ikuti prinsip performa berikut:
Membaca lebih sedikit baris dan kolom: Optimalkan kueri untuk mengambil data yang diperlukan saja. Minimalkan jumlah data yang dibaca dari database, karena pengambilan data yang berlebihan dapat memengaruhi performa.
Mendorong tugas ke mesin SQLite: Lakukan operasi komputasi, pemfilteran, dan pengurutan dalam kueri SQL. Menggunakan mesin kueri SQLite dapat meningkatkan performa secara signifikan.
Mengubah skema database: Desain skema database Anda untuk membantu SQLite membuat rencana kueri dan representasi data yang efisien. Indeks tabel dengan benar dan optimalkan struktur tabel untuk meningkatkan performa.
Selain itu, Anda dapat menggunakan alat pemecahan masalah yang tersedia untuk mengukur performa database SQLite untuk membantu mengidentifikasi area yang memerlukan pengoptimalan.
Sebaiknya gunakan library Jetpack Room.
Mengonfigurasi database untuk meningkatkan performa
Ikuti langkah-langkah di bagian ini untuk mengonfigurasi database Anda agar performanya optimal di SQLite.
Mengaktifkan Write-Ahead Logging
SQLite menerapkan mutasi dengan menambahkannya ke log, yang terkadang dipadatkan ke dalam database. Tindakan ini disebut Write-Ahead Logging (WAL).
Aktifkan WAL
kecuali jika Anda menggunakan ATTACH DATABASE.
Melonggarkan mode sinkronisasi
Saat menggunakan WAL, secara default setiap commit akan mengeluarkan fsync untuk membantu memastikan bahwa
data mencapai disk. Hal ini meningkatkan ketahanan data, tetapi memperlambat commit Anda.
SQLite memiliki opsi untuk mengontrol mode sinkron. Jika Anda mengaktifkan WAL, setel mode sinkron ke NORMAL:
// When opening the database
val paramsBuilder: SQLiteDatabase.OpenParams.Builder = SQLiteDatabase.OpenParams.Builder()
paramsBuilder.journalMode = SQLiteDatabase.SYNC_MODE_NORMAL
// Or: after having opened the database
db.execSQL("PRAGMA synchronous = NORMAL");
Di setelan ini, commit dapat ditampilkan sebelum data disimpan di disk. Jika penonaktifan perangkat terjadi, misalnya karena kehilangan daya atau kernel panic, data yang di-commit bisa saja hilang. Namun, karena logging, database Anda tidak rusak.
Jika hanya aplikasi Anda yang error, data akan tetap masuk ke disk. Untuk sebagian besar aplikasi, setelan ini menghasilkan peningkatan performa tanpa biaya material.
Menentukan skema tabel yang efisien
Untuk mengoptimalkan performa dan meminimalkan konsumsi data, tentukan skema tabel yang efisien. SQLite membuat data dan rencana kueri yang efisien, yang mengarah ke pengambilan data yang lebih cepat. Bagian ini memberikan praktik terbaik untuk membuat skema tabel.
Pertimbangkan INTEGER PRIMARY KEY
Untuk contoh ini, tentukan dan isi tabel sebagai berikut:
CREATE TABLE Customers(
id INTEGER,
name TEXT,
city TEXT
);
INSERT INTO Customers Values(456, 'John Lennon', 'Liverpool, England');
INSERT INTO Customers Values(123, 'Michael Jackson', 'Gary, IN');
INSERT INTO Customers Values(789, 'Dolly Parton', 'Sevier County, TN');
Output tabelnya adalah sebagai berikut:
| rowid | id | nama | kota |
|---|---|---|---|
| 1 | 456 | John Lennon | Liverpool, Inggris |
| 2 | 123 | Michael Jackson | Gary, IN |
| 3 | 789 | Dolly Parton | Sevier County, TN |
Kolom rowid adalah
indeks yang mempertahankan urutan penyisipan. Kueri yang
memfilter menurut rowid diimplementasikan sebagai penelusuran hierarki B yang cepat, tetapi kueri yang
memfilter menurut id merupakan pemindaian tabel yang lambat.
Jika berencana melakukan pencarian menurut id, Anda dapat menghindari penyimpanan
kolom rowid untuk mendapatkan lebih sedikit data dalam penyimpanan dan database
yang lebih cepat secara keseluruhan:
CREATE TABLE Customers(
id INTEGER PRIMARY KEY,
name TEXT,
city TEXT
);
Tabel Anda sekarang terlihat seperti berikut:
| id | nama | kota |
|---|---|---|
| 123 | Michael Jackson | Gary, IN |
| 456 | John Lennon | Liverpool, Inggris |
| 789 | Dolly Parton | Sevier County, TN |
Karena Anda tidak perlu menyimpan kolom rowid, kueri id dapat dipercepat. Perhatikan
bahwa tabel kini diurutkan berdasarkan id, bukan urutan penyisipan.
Mempercepat kueri dengan indeks
SQLite menggunakan
indeks
untuk mempercepat kueri. Saat memfilter (WHERE), mengurutkan (ORDER BY), atau
menggabungkan (GROUP BY) kolom, jika tabel memiliki indeks untuk kolom tersebut, kueri akan dipercepat.
Pada contoh sebelumnya, pemfilteran menurut city mengharuskan pemindaian seluruh tabel:
SELECT id, name
WHERE city = 'London, England';
Untuk aplikasi dengan banyak kueri kota, Anda dapat mempercepat kueri tersebut dengan indeks:
CREATE INDEX city_index ON Customers(city);
Indeks diterapkan sebagai tabel tambahan, yang diurutkan berdasarkan kolom indeks dan
dipetakan ke rowid:
| kota | rowid |
|---|---|
| Gary, IN | 2 |
| Liverpool, Inggris | 1 |
| Sevier County, TN | 3 |
Perhatikan bahwa biaya penyimpanan kolom city sekarang menjadi dua kali lipat, karena kolom tersebut
kini ada di tabel asli dan indeks. Karena Anda menggunakan
indeks, biaya penyimpanan tambahan sebanding dengan keuntungannya, yaitu kueri yang lebih cepat.
Namun, jangan mempertahankan indeks yang tidak Anda gunakan agar tidak membayar
biaya penyimpanan tanpa mendapatkan peningkatan performa kueri.
Membuat indeks multi-kolom
Jika kueri menggabungkan beberapa kolom, Anda dapat membuat indeks multi-kolom untuk sepenuhnya mempercepat kueri. Anda juga dapat menggunakan indeks di kolom luar dan memungkinkan penelusuran di dalam dilakukan sebagai pemindaian linear.
Misalnya, dengan kueri berikut:
SELECT id, name
WHERE city = 'London, England'
ORDER BY city, name
Anda dapat mempercepat kueri dengan indeks multi-kolom dalam urutan yang sama seperti yang ditentukan dalam kueri:
CREATE INDEX city_name_index ON Customers(city, name);
Namun, jika Anda hanya memiliki indeks di city, pengurutan di luar tetap
dipercepat, sedangkan pengurutan di dalam memerlukan pemindaian linear.
Hal ini juga berfungsi dengan pertanyaan awalan. Misalnya, indeks
ON Customers (city, name) juga mempercepat pemfilteran, pengurutan, dan pengelompokan
menurut city, karena tabel indeks untuk indeks multi-kolom diurutkan menurut
indeks tertentu dalam urutan tertentu.
Mempertimbangkan WITHOUT ROWID
Secara default, SQLite membuat kolom rowid untuk tabel Anda, dengan rowid sebagai
INTEGER PRIMARY KEY AUTOINCREMENT implisit. Jika Anda sudah memiliki kolom yang
merupakan INTEGER PRIMARY KEY, kolom ini akan menjadi alias dari rowid.
Untuk tabel yang memiliki kunci utama selain INTEGER atau gabungan
kolom, pertimbangkan WITHOUT ROWID.
Menyimpan data kecil sebagai BLOB dan data besar sebagai file
Jika ingin mengaitkan data besar dengan baris, seperti thumbnail gambar atau foto untuk kontak, Anda dapat menyimpan data tersebut dalam kolom BLOB atau dalam file, lalu menyimpan jalur dalam kolom.
File biasanya dibulatkan ke atas hingga tambahan 4 KB. Untuk file yang sangat kecil, dengan error pembulatan yang signifikan, akan lebih efisien untuk menyimpannya dalam database sebagai BLOB. SQLite meminimalkan panggilan sistem file dan lebih
cepat daripada sistem file yang mendasarinya dalam beberapa kasus.
Meningkatkan performa kueri
Ikuti praktik terbaik ini untuk meningkatkan performa kueri di SQLite dengan meminimalkan waktu respons dan memaksimalkan efisiensi pemrosesan.
Hanya baca baris yang diperlukan
Filter memungkinkan Anda mempersempit hasil dengan menentukan kriteria tertentu, seperti rentang tanggal, lokasi, atau nama. Batas memungkinkan Anda mengontrol jumlah hasil yang dilihat:
db.rawQuery("""
SELECT name
FROM Customers
LIMIT 10;
""".trimIndent(),
null
).use { cursor ->
while (cursor.moveToNext()) {
// Process cursor data
}
}
Hanya baca kolom yang diperlukan
Hindari memilih kolom yang tidak diperlukan, yang dapat memperlambat kueri dan membuang resource. Sebagai gantinya, hanya pilih kolom yang digunakan.
Pada contoh berikut, Anda memilih id, name, dan phone:
// This is not the most efficient way of doing this.
// See the following example for a better approach.
db.rawQuery(
"""
SELECT id, name, phone
FROM customers;
""".trimIndent(),
null
).use { cursor ->
while (cursor.moveToNext()) {
val name = cursor.getString(1)
// Further processing
}
}
Namun, Anda hanya memerlukan kolom name:
db.rawQuery("""
SELECT name
FROM Customers;
""".trimIndent(),
null
).use { cursor ->
while (cursor.moveToNext()) {
val name = cursor.getString(0)
// Further processing
}
}
Membuat parameter kueri
String kueri Anda mungkin menyertakan parameter yang hanya diketahui saat runtime, seperti berikut:
fun getNameById(id: Long): String?
db.rawQuery(
"SELECT name FROM customers WHERE id=$id", null
).use { cursor ->
return if (cursor.moveToFirst()) {
cursor.getString(0)
} else {
null
}
}
}
Dalam kode sebelumnya, setiap kueri membuat string yang berbeda, sehingga tidak mendapatkan manfaat dari cache pernyataan. Setiap panggilan mengharuskan SQLite untuk mengompilasinya sebelum dapat dieksekusi. Sebagai gantinya, Anda dapat mengganti argumen id dengan a
parameter dan
mengikat nilai dengan selectionArgs:
fun getNameById(id: Long): String? {
db.rawQuery(
"""
SELECT name
FROM customers
WHERE id=?
""".trimIndent(), arrayOf(id.toString())
).use { cursor ->
return if (cursor.moveToFirst()) {
cursor.getString(0)
} else {
null
}
}
}
Sekarang kueri dapat dikompilasi satu kali dan di-cache. Kueri yang dikompilasi digunakan kembali di antara pemanggilan getNameById(long) yang berbeda.
Melakukan iterasi di SQL, bukan dalam kode
Gunakan satu kueri yang menampilkan semua hasil yang ditargetkan, bukan loop terprogram yang melakukan iterasi pada kueri SQL untuk menampilkan hasil individual. Loop terprogram sekitar 1.000 kali lebih lambat daripada satu kueri SQL.
Menggunakan DISTINCT untuk nilai unik
Menggunakan kata kunci DISTINCT dapat meningkatkan performa kueri dengan
mengurangi jumlah data yang perlu diproses. Misalnya, jika Anda ingin menampilkan nilai unik saja dari kolom, gunakan DISTINCT:
db.rawQuery("""
SELECT DISTINCT name
FROM Customers;
""".trimIndent(),
null
).use { cursor ->
while (cursor.moveToNext()) {
// Only iterate over distinct names in Kotlin
// Process distinct name
}
}
Menggunakan fungsi gabungan jika memungkinkan
Gunakan fungsi agregat untuk hasil gabungan tanpa data baris. Misalnya, kode berikut memeriksa apakah ada setidaknya satu baris yang cocok:
// This is not the most efficient way of doing this.
// See the following example for a better approach.
db.rawQuery("""
SELECT id, name
FROM Customers
WHERE city = 'Paris';
""".trimIndent(),
null
).use { cursor ->
if (cursor.moveToFirst()) {
// At least one customer from Paris
// Handle found
} else {
// No customers from Paris
// Handle not found
}
Untuk mengambil baris pertama saja, Anda dapat menggunakan EXISTS() untuk menampilkan 0 jika tidak ada baris yang cocok, dan 1 jika satu atau beberapa baris cocok:
db.rawQuery("""
SELECT EXISTS (
SELECT null
FROM Customers
WHERE city = 'Paris';
);
""".trimIndent(),
null
).use { cursor ->
if (cursor.moveToFirst() && cursor.getInt(0) == 1) {
// At least one customer from Paris
// Handle found
} else {
// No customers from Paris
// Handle not found
}
}
Gunakan fungsi agregat SQLite dalam kode aplikasi Anda:
COUNT: menghitung jumlah baris dalam kolom.SUM: menambahkan semua nilai numerik dalam kolom.MINatauMAX: menentukan nilai terendah atau tertinggi. Berfungsi untuk kolom numerik, jenisDATE, dan jenis teks.AVG: menemukan nilai numerik rata-rata.GROUP_CONCAT: menyambungkan string dengan pemisah opsional.
Menggunakan COUNT(), bukan Cursor.getCount()
Dalam
contoh berikut, fungsi
Cursor.getCount() membaca semua baris dari database dan menampilkan semua nilai baris:
// This is not the most efficient way of doing this.
// See the following example for a better approach.
db.rawQuery("""
SELECT id
FROM Customers;
""".trimIndent(),
null
).use { cursor ->
val count = cursor.getCount()
// Use count
}
Namun, dengan menggunakan COUNT(), database hanya menampilkan jumlah:
db.rawQuery("""
SELECT COUNT(*)
FROM Customers;
""".trimIndent(),
null
).use { cursor ->
cursor.moveToFirst()
val count = cursor.getInt(0)
// Use count
}
Kueri Nest, bukan kode
SQL adalah composable dan mendukung subkueri, gabungan, dan batasan kunci asing. Anda dapat menggunakan hasil dari satu kueri untuk kueri lain tanpa memeriksa kode aplikasi. Hal ini mengurangi kebutuhan untuk menyalin data dari SQLite dan memungkinkan mesin database mengoptimalkan kueri Anda.
Pada contoh berikut, Anda dapat menjalankan kueri untuk menemukan kota yang memiliki pelanggan terbanyak, lalu menggunakan hasil dalam kueri lain untuk menemukan semua pelanggan dari kota tersebut:
// This is not the most efficient way of doing this.
// See the following example for a better approach.
db.rawQuery("""
SELECT city
FROM Customers
GROUP BY city
ORDER BY COUNT(*) DESC
LIMIT 1;
""".trimIndent(),
null
).use { cursor ->
if (cursor.moveToFirst()) {
val topCity = cursor.getString(0)
db.rawQuery("""
SELECT name, city
FROM Customers
WHERE city = ?;
""".trimIndent(),
arrayOf(topCity)).use { innerCursor ->
while (innerCursor.moveToNext()) {
// Process inner cursor data
}
}
}
}
Untuk mendapatkan hasilnya dengan durasi waktu setengah saja dari contoh sebelumnya, gunakan satu kueri SQL dengan pernyataan bertingkat:
db.rawQuery("""
SELECT name, city
FROM Customers
WHERE city IN (
SELECT city
FROM Customers
GROUP BY city
ORDER BY COUNT (*) DESC
LIMIT 1;
);
""".trimIndent(),
null
).use { cursor ->
if (cursor.moveToNext()) {
// Process cursor data
}
}
Memeriksa keunikan di SQL
Jika baris tidak boleh disisipkan kecuali nilai kolom tertentu bersifat unik dalam tabel, akan lebih efisien untuk menerapkan keunikan tersebut sebagai batasan kolom.
Dalam contoh berikut, satu kueri dijalankan untuk memvalidasi baris yang akan disisipkan dan baris lain untuk benar-benar disisipkan:
// This is not the most efficient way of doing this.
// See the following example for a better approach.
db.rawQuery(
"""
SELECT EXISTS (
SELECT null
FROM customers
WHERE username = ?
);
""".trimIndent(),
arrayOf(customer.username)
).use { cursor ->
if (cursor.moveToFirst() && cursor.getInt(0) == 1) {
throw AddCustomerException(customer)
}
}
db.execSQL(
"INSERT INTO customers VALUES (?, ?, ?)",
arrayOf(
customer.id.toString(),
customer.name,
customer.username
)
)
Daripada memeriksa batasan unik di Kotlin, Anda dapat memeriksanya di SQL saat menentukan tabel:
CREATE TABLE Customers(
id INTEGER PRIMARY KEY,
name TEXT,
username TEXT UNIQUE
);
SQLite melakukan hal yang sama dengan berikut ini:
CREATE TABLE Customers(...);
CREATE UNIQUE INDEX CustomersUsername ON Customers(username);
Sekarang Anda dapat menyisipkan baris dan membiarkan SQLite memeriksa batasannya:
try {
db.execSql(
"INSERT INTO Customers VALUES (?, ?, ?)",
arrayOf(customer.id.toString(), customer.name, customer.username)
)
} catch(e: SQLiteConstraintException) {
throw AddCustomerException(customer, e)
}
SQLite mendukung indeks unik dengan beberapa kolom:
CREATE TABLE table(...);
CREATE UNIQUE INDEX unique_table ON table(column1, column2, ...);
SQLite memvalidasi batasan lebih cepat dan dengan overhead yang lebih sedikit daripada kode Kotlin. Praktik terbaiknya adalah menggunakan SQLite, bukan kode aplikasi
Mengelompokkan beberapa penyisipan dalam satu transaksi
Suatu transaksi meng-commit beberapa operasi, yang tidak hanya meningkatkan efisiensi, tetapi juga ketepatan. Untuk meningkatkan konsistensi data dan mempercepat performa, Anda dapat mengelompokkan penyisipan:
db.beginTransaction()
try {
customers.forEach { customer ->
db.execSql(
"INSERT INTO Customers VALUES (?, ?, ?)",
arrayOf(customer.id.toString(), customer.name, "customerValue")
)
}
} finally {
db.endTransaction()
}
Menggunakan alat pemecahan masalah
SQLite menyediakan alat pemecahan masalah berikut untuk membantu mengukur performa.
Menggunakan perintah interaktif SQLite
Jalankan SQLite di komputer Anda untuk menjalankan kueri dan belajar.
Versi platform Android yang berbeda menggunakan revisi SQLite yang berbeda. Untuk menggunakan
mesin yang sama dengan yang ada di perangkat Android, gunakan adb shell dan
jalankan sqlite3 di perangkat target Anda.
Anda dapat meminta SQLite untuk menghitung waktu kueri:
sqlite> .timer on
sqlite> SELECT ...
Run Time: real ... user ... sys ...
EXPLAIN QUERY PLAN
Anda dapat meminta SQLite untuk menjelaskan cara menjawab kueri dengan menggunakan
EXPLAIN QUERY PLAN:
sqlite> EXPLAIN QUERY PLAN
SELECT id, name
FROM Customers
WHERE city = 'Paris';
QUERY PLAN
`--SCAN Customers
Contoh sebelumnya memerlukan pemindaian tabel penuh tanpa indeks untuk menemukan semua pelanggan dari Paris. Hal ini disebut kompleksitas linear. SQLite perlu membaca semua baris dan hanya menyimpan baris yang cocok dengan pelanggan dari Paris. Untuk memperbaikinya, Anda dapat menambahkan indeks:
sqlite> CREATE INDEX Idx1 ON Customers(city);
sqlite> EXPLAIN QUERY PLAN
SELECT id, name
FROM Customers
WHERE city = 'Paris';
QUERY PLAN
`--SEARCH test USING INDEX Idx1 (city=?
Jika menggunakan shell interaktif, Anda dapat meminta SQLite untuk selalu menjelaskan rencana kueri:
sqlite> .eqp on
Untuk mengetahui informasi selengkapnya, lihat Perencanaan Kueri.
Penganalisis SQLite
SQLite menawarkan antarmuka command line (CLI) sqlite3_analyzer untuk membuang
informasi tambahan yang dapat digunakan untuk memecahkan masalah performa. Untuk menginstal,
buka Halaman Download SQLite.
Anda dapat menggunakan adb pull untuk mendownload file database dari perangkat target ke workstation untuk dianalisis:
adb pull /data/data/<app_package_name>/databases/<db_name>.db
Browser SQLite
Anda juga dapat menginstal alat GUI Browser SQLite di halaman Download SQLite.
Logging Android
Android akan menghitung waktu kueri SQLite dan mencatatnya untuk Anda:
# Enable query time logging
$ adb shell setprop log.tag.SQLiteTime VERBOSE
# Disable query time logging
$ adb shell setprop log.tag.SQLiteTime ERROR
Pelacakan Perfetto
Saat mengonfigurasi Perfetto, Anda dapat menambahkan hal berikut untuk menyertakan jalur untuk kueri individual:
data_sources {
config {
name: "linux.ftrace"
ftrace_config {
atrace_categories: "database"
}
}
}
dumpsys meminfo
adb shell dumpsys meminfo <package-name> akan mencetak statistik terkait penggunaan memori aplikasi, termasuk beberapa detail tentang memori SQLite. Misalnya, statistik ini diambil dari output adb shell dumpsys meminfo com.google.android.gms.persistent di perangkat developer:
DATABASES
pgsz dbsz Lookaside(b) cache hits cache misses cache size Dbname
PER CONNECTION STATS
4 52 45 8 41 6 /data/user/10/com.google.android.gms/databases/gaia-discovery
4 8 0 0 0 (attached) temp
4 52 56 5 23 6 /data/user/10/com.google.android.gms/databases/gaia-discovery (1)
4 252 95 233 124 12 /data/user_de/10/com.google.android.gms/databases/phenotype.db
4 8 0 0 0 (attached) temp
4 252 17 0 17 1 /data/user_de/10/com.google.android.gms/databases/phenotype.db (1)
4 9280 105 103169 69805 25 /data/user/10/com.google.android.gms/databases/phenotype.db
4 20 0 0 0 (attached) temp
4 9280 108 13877 6394 25 /data/user/10/com.google.android.gms/databases/phenotype.db (2)
4 8 0 0 0 (attached) temp
4 9280 105 12548 5519 25 /data/user/10/com.google.android.gms/databases/phenotype.db (3)
4 8 0 0 0 (attached) temp
4 9280 107 18328 7886 25 /data/user/10/com.google.android.gms/databases/phenotype.db (1)
4 8 0 0 0 (attached) temp
4 36 51 156 29 5 /data/user/10/com.google.android.gms/databases/mobstore_gc_db_v0
4 36 97 47 27 10 /data/user/10/com.google.android.gms/databases/context_feature_default.db
4 36 56 3 16 4 /data/user/10/com.google.android.gms/databases/context_feature_default.db (2)
4 300 40 2111 24 5 /data/user/10/com.google.android.gms/databases/gservices.db
4 300 39 3 17 4 /data/user/10/com.google.android.gms/databases/gservices.db (1)
4 20 17 0 14 1 /data/user/10/com.google.android.gms/databases/gms.notifications.db
4 20 33 1 15 2 /data/user/10/com.google.android.gms/databases/gms.notifications.db (1)
4 120 40 143 163 4 /data/user/10/com.google.android.gms/databases/android_pay
4 120 123 86 32 19 /data/user/10/com.google.android.gms/databases/android_pay (1)
4 28 33 4 17 3 /data/user/10/com.google.android.gms/databases/googlesettings.db
POOL STATS
cache hits cache misses cache size Dbname
13 68 81 /data/user/10/com.google.android.gms/databases/gaia-discovery
233 145 378 /data/user_de/10/com.google.android.gms/databases/phenotype.db
147921 89616 237537 /data/user/10/com.google.android.gms/databases/phenotype.db
156 30 186 /data/user/10/com.google.android.gms/databases/mobstore_gc_db_v0
50 57 107 /data/user/10/com.google.android.gms/databases/context_feature_default.db
2114 43 2157 /data/user/10/com.google.android.gms/databases/gservices.db
1 31 32 /data/user/10/com.google.android.gms/databases/gms.notifications.db
229 197 426 /data/user/10/com.google.android.gms/databases/android_pay
4 18 22 /data/user/10/com.google.android.gms/databases/googlesettings.db
Di bagian DATABASES, Anda akan menemukan:
pgsz: ukuran satu halaman database, dalam KB.dbsz: ukuran seluruh database, dalam halaman. Untuk mendapatkan ukuran dalam KB, kalikanpgszdengandbsz.Lookaside(b): memori yang dialokasikan ke buffer lookaside SQLite per koneksi, dalam byte. Biasanya ukurannya sangat kecil.cache hits: SQLite mempertahankan cache halaman database. Ini adalah jumlah cache halaman yang ditemukan (jumlah).cache misses: jumlah cache halaman yang tidak ditemukan (jumlah).cache size: jumlah halaman dalam cache (jumlah). Untuk mendapatkan ukuran dalam KB, kalikan angka ini denganpgsz.Dbname: jalur ke file DB. Dalam contoh kami, beberapa DB memiliki(1)atau angka lain yang ditambahkan ke namanya, untuk menunjukkan bahwa ada lebih dari satu koneksi ke database yang mendasarinya. Statistik dilacak per koneksi.
Di bagian POOL STATS, Anda akan menemukan:
cache hits: SQLite meng-cache pernyataan yang disiapkan dan mencoba menggunakannya kembali saat menjalankan kueri, untuk menghemat upaya dan memori dalam mengompilasi pernyataan SQL. Ini adalah jumlah cache pernyataan yang ditemukan (jumlah).cache misses: jumlah cache pernyataan yang tidak ditemukan (jumlah).cache size: dimulai dengan Android 17, ini mencantumkan jumlah total pernyataan yang disiapkan dalam cache. Pada versi sebelumnya, nilai ini setara dengan jumlah hit dan miss yang tercantum di dua kolom lainnya, dan tidak mewakili ukuran cache.
Referensi lainnya
Konten Views
Direkomendasikan untuk Anda
- Catatan: teks link ditampilkan saat JavaScript nonaktif
- Menjalankan benchmark dalam Continuous Integration
- Periode frozen
- Membuat dan mengukur Profil Dasar Pengukuran tanpa Macrobenchmark