SQLite performansı için en iyi uygulamalar

Android, verimli bir SQL veritabanı olan SQLite için yerleşik destek sunar. Uygulamanızın performansını optimize etmek için aşağıdaki en iyi uygulamaları izleyin. Böylece, verileriniz büyüdükçe uygulamanızın hızlı ve öngörülebilir şekilde hızlı kalmasını sağlayabilirsiniz. Bu en iyi uygulamaları kullanarak, yeniden üretilmesi ve sorun giderilmesi zor olan performans sorunlarıyla karşılaşma olasılığını da azaltırsınız.

Daha hızlı performans elde etmek için aşağıdaki performans ilkelerini uygulayın:

  • Daha az satır ve sütun okuma: Sorgularınızı yalnızca gerekli verileri alacak şekilde optimize edin. Veritabanından okunan veri miktarını en aza indirin. Çünkü aşırı veri alma işlemi performansı etkileyebilir.

  • İşi SQLite motoruna aktarma: SQL sorgularında hesaplama, filtreleme ve sıralama işlemleri gerçekleştirin. SQLite'ın sorgu motorunu kullanmak performansı önemli ölçüde artırabilir.

  • Veritabanı şemasını değiştirme: SQLite'ın etkili sorgu planları ve veri temsilleri oluşturmasına yardımcı olmak için veritabanı şemanızı tasarlayın. Performansı artırmak için tabloları düzgün şekilde dizine ekleyin ve tablo yapılarını optimize edin.

Ayrıca, optimizasyon gerektiren alanları belirlemeye yardımcı olmak için SQLite veritabanınızın performansını ölçmek üzere mevcut sorun giderme araçlarını kullanabilirsiniz.

Jetpack Room kitaplığını kullanmanızı öneririz.

Veritabanını performans için yapılandırma

SQLite'te optimum performans için veritabanınızı yapılandırmak üzere bu bölümdeki adımları uygulayın.

Yazma öncesi günlük kaydını etkinleştirme

SQLite, mutasyonları bir günlük dosyasına ekleyerek uygular. Bu günlük dosyası, zaman zaman veritabanında sıkıştırılır. Buna Yazma Öncesi Günlük Kaydı (WAL) denir.

ATTACH DATABASE kullanmıyorsanız WAL'ı etkinleştirin.

Senkronizasyon modunu rahatlatma

WAL kullanılırken varsayılan olarak her commit, verilerin diske ulaşmasını sağlamak için bir fsync yayınlar. Bu, verilerin dayanıklılığını artırır ancak işlemelerinizi yavaşlatır.

SQLite'ta senkron modu kontrol etme seçeneği vardır. WAL'ı etkinleştirirseniz senkron modu NORMAL olarak ayarlayın:

// 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");

Bu ayarda, veriler diske depolanmadan önce bir işlem döndürülebilir. Güç kaybı veya çekirdek panik gibi bir cihaz kapatma işlemi gerçekleşirse kaydedilen veriler kaybolabilir. Ancak günlük kaydı nedeniyle veritabanınız bozulmaz.

Yalnızca uygulamanız kilitlenirse verileriniz diske ulaşmaya devam eder. Çoğu uygulama için bu ayar, önemli bir maliyet olmadan performans iyileştirmeleri sağlar.

Verimli tablo şemaları tanımlama

Performansı optimize etmek ve veri tüketimini en aza indirmek için verimli bir tablo şeması tanımlayın. SQLite, verimli sorgu planları ve veriler oluşturarak daha hızlı veri alımına olanak tanır. Bu bölümde, tablo şemaları oluşturmayla ilgili en iyi uygulamalar verilmiştir.

INTEGER PRIMARY KEY kategorisini düşünün

Bu örnek için bir tabloyu aşağıdaki gibi tanımlayın ve doldurun:

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');

Tablo çıkışı aşağıdaki gibidir:

rowid id ad şehir
1 456 John Lennon Liverpool, İngiltere
2 123 Michael Jackson Gary, IN
3 789 Dolly Parton Sevier County, TN

rowid sütunu, ekleme sırasını koruyan bir dizindir. rowid ile filtreleyen sorgular hızlı bir B-ağacı araması olarak uygulanır ancak id ile filtreleyen sorgular yavaş bir tablo taramasıdır.

id ile arama yapmayı planlıyorsanız depolama alanında daha az veri ve genel olarak daha hızlı bir veritabanı için rowid sütununu depolamaktan kaçınabilirsiniz:

CREATE TABLE Customers(
  id INTEGER PRIMARY KEY,
  name TEXT,
  city TEXT
);

Tablonuz artık aşağıdaki gibi görünüyor:

id ad şehir
123 Michael Jackson Gary, IN
456 John Lennon Liverpool, İngiltere
789 Dolly Parton Sevier County, TN

rowid sütununu saklamanız gerekmediğinden id sorguları hızlıdır. Tablonun artık kampanya siparişi yerine id temelinde sıralandığını unutmayın.

Dizinlerle sorguları hızlandırma

SQLite, sorguları hızlandırmak için dizinleri kullanır. Bir sütun filtrelenirken (WHERE), sıralanırken (ORDER BY) veya toplanırken (GROUP BY) tabloda sütun için bir dizin varsa sorgu hızlandırılır.

Önceki örnekte, city ile filtreleme yapmak için tablonun tamamının taranması gerekir:

SELECT id, name
WHERE city = 'London, England';

Çok sayıda şehir sorgusu olan bir uygulamada, bu sorguları bir dizinle hızlandırabilirsiniz:

CREATE INDEX city_index ON Customers(city);

Dizin, dizin sütununa göre sıralanmış ve rowid ile eşlenmiş ek bir tablo olarak uygulanır:

şehir rowid
Gary, IN 2
Liverpool, İngiltere 1
Sevier County, TN 3

city sütununun depolama maliyetinin artık iki katına çıktığını unutmayın. Bunun nedeni, sütunun hem orijinal tabloda hem de dizinde bulunmasıdır. Dizini kullandığınız için eklenen depolama alanının maliyeti, daha hızlı sorguların avantajına değer. Ancak sorgu performansı artışı olmadan depolama maliyeti ödememek için kullanmadığınız bir dizini korumayın.

Çok sütunlu dizinler oluşturma

Sorgularınız birden fazla sütunu birleştiriyorsa sorguyu tam olarak hızlandırmak için çok sütunlu dizinler oluşturabilirsiniz. Ayrıca, dış sütunda bir dizin kullanabilir ve iç aramanın doğrusal tarama olarak yapılmasını sağlayabilirsiniz.

Örneğin, şu sorgu verildiğinde:

SELECT id, name
WHERE city = 'London, England'
ORDER BY city, name

Sorguda belirtilen sırayla çok sütunlu bir dizin kullanarak sorguyu hızlandırabilirsiniz:

CREATE INDEX city_name_index ON Customers(city, name);

Ancak yalnızca city üzerinde bir dizininiz varsa dış sıralama yine hızlandırılırken iç sıralama için doğrusal tarama gerekir.

Bu özellik, önek sorgularıyla da çalışır. Örneğin, bir dizin ON Customers (city, name), çok sütunlu bir dizinin dizin tablosu belirli bir sırayla belirli dizinlere göre sıralandığından city ile filtreleme, sıralama ve gruplandırma işlemlerini de hızlandırır.

WITHOUT ROWID kategorisini düşünün

SQLite, varsayılan olarak tablonuz için bir rowid sütunu oluşturur. Burada rowid, örtülü bir INTEGER PRIMARY KEY AUTOINCREMENT'dir. Zaten INTEGER PRIMARY KEY olan bir sütununuz varsa bu sütun, rowid'nin takma adı olur.

INTEGER dışında bir birincil anahtarı olan veya sütunların bileşimi olan tablolar için WITHOUT ROWID'ı kullanabilirsiniz.

Küçük verileri BLOB olarak, büyük verileri ise dosya olarak depolama

Bir satırla büyük verileri (ör. resmin küçük resmi veya bir kişi için fotoğraf) ilişkilendirmek istiyorsanız verileri BLOB sütununda veya bir dosyada saklayıp yolu sütunda saklayabilirsiniz.

Dosyalar genellikle 4 KB'lık artışlarla yuvarlanır. Yuvarlama hatasının önemli olduğu çok küçük dosyaları veritabanında BLOB olarak depolamak daha verimlidir. SQLite, dosya sistemi çağrılarını en aza indirir ve bazı durumlarda temel dosya sisteminden daha hızlıdır.

Sorgu performansını artırma

Yanıt sürelerini en aza indirerek ve işlem verimliliğini en üst düzeye çıkararak SQLite'te sorgu performansını artırmak için aşağıdaki en iyi uygulamalardan yararlanın.

Yalnızca ihtiyacınız olan satırları okuma

Filtreler, tarih aralığı, konum veya ad gibi belirli ölçütleri belirterek sonuçlarınızı daraltmanıza olanak tanır. Sınırlar, gördüğünüz sonuçların sayısını kontrol etmenize olanak tanır:

db.rawQuery("""
    SELECT name
    FROM Customers
    LIMIT 10;
    """.trimIndent(),
    null
).use { cursor ->
    while (cursor.moveToNext()) {
        // Process cursor data
    }
}

Yalnızca ihtiyacınız olan sütunları okuma

Gereksiz sütunları seçmekten kaçının. Bu sütunlar sorgularınızı yavaşlatabilir ve kaynaklarınızı boşa harcayabilir. Bunun yerine, yalnızca kullanılan sütunları seçin.

Aşağıdaki örnekte id, name ve phone'yi seçiyorsunuz:

// 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
    }
}

Ancak yalnızca name sütununa ihtiyacınız vardır:

db.rawQuery("""
    SELECT name
    FROM Customers;
    """.trimIndent(),
    null
).use { cursor ->
    while (cursor.moveToNext()) {
        val name = cursor.getString(0)
        // Further processing
    }
}

Sorguları parametrelendirme

Sorgu dizeniz, yalnızca çalışma zamanında bilinen bir parametre içerebilir. Örneğin:

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
        }
    }
}

Önceki kodda her sorgu farklı bir dize oluşturur ve bu nedenle ifade önbelleğinden yararlanmaz. Her çağrının yürütülebilmesi için önce SQLite tarafından derlenmesi gerekir. Bunun yerine, id bağımsız değişkenini bir parametreyle değiştirebilir ve değeri selectionArgs ile bağlayabilirsiniz:

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
        }
    }
}

Artık sorgu bir kez derlenip önbelleğe alınabilir. Derlenen sorgu, getNameById(long) öğesinin farklı çağrıları arasında yeniden kullanılır.

Kodda değil SQL'de yineleme yapın

Tek tek sonuçları döndürmek için SQL sorgularında yineleme yapan programatik bir döngü yerine, hedeflenen tüm sonuçları döndüren tek bir sorgu kullanın. Programatik döngü, tek bir SQL sorgusundan yaklaşık 1.000 kat daha yavaştır.

Benzersiz değerler için DISTINCT kullanın

DISTINCT anahtar kelimesini kullanmak, işlenmesi gereken veri miktarını azaltarak sorgularınızın performansını artırabilir. Örneğin, bir sütundaki yalnızca benzersiz değerleri döndürmek istiyorsanız DISTINCT işlevini kullanın:

db.rawQuery("""
    SELECT DISTINCT name
    FROM Customers;
    """.trimIndent(),
    null
).use { cursor ->
    while (cursor.moveToNext()) {
        // Only iterate over distinct names in Kotlin
        // Process distinct name
    }
}

Mümkün olduğunda toplama işlevlerini kullanın

Satır verileri olmadan toplu sonuçlar için toplama işlevlerini kullanın. Örneğin, aşağıdaki kod en az bir eşleşen satır olup olmadığını kontrol eder:

// 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
}

Yalnızca ilk satırı getirmek için eşleşen bir satır yoksa 0, bir veya daha fazla satır eşleşiyorsa 1 döndürmek üzere EXISTS() işlevini kullanabilirsiniz:

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
    }
}

Uygulama kodunuzda SQLite toplama işlevlerini kullanın:

  • COUNT: Bir sütunda kaç satır olduğunu sayar.
  • SUM: Bir sütundaki tüm sayısal değerleri toplar.
  • MIN veya MAX: En düşük ya da en yüksek değeri belirler. Sayısal sütunlar, DATE türleri ve metin türleri için çalışır.
  • AVG: Sayısal değerin ortalamasını bulur.
  • GROUP_CONCAT: Dizeleri isteğe bağlı bir ayırıcıyla birleştirir.

Cursor.getCount() yerine COUNT() kullanın

Aşağıdaki örnekte, Cursor.getCount() işlevi veritabanındaki tüm satırları okur ve tüm satır değerlerini döndürür:

// 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
}

Ancak COUNT() kullanıldığında veritabanı yalnızca sayıyı döndürür:

db.rawQuery("""
    SELECT COUNT(*)
    FROM Customers;
    """.trimIndent(),
    null
).use { cursor ->
    cursor.moveToFirst()
    val count = cursor.getInt(0)
    // Use count
}

Kod yerine iç içe yerleştirilmiş sorgular

SQL, birleştirilebilir ve alt sorguları, birleştirmeleri ve yabancı anahtar kısıtlamalarını destekler. Uygulama koduna gitmeden bir sorgunun sonucunu başka bir sorguda kullanabilirsiniz. Bu, SQLite'tan veri kopyalama ihtiyacını azaltır ve veritabanı motorunun sorgunuzu optimize etmesine olanak tanır.

Aşağıdaki örnekte, en çok müşteriye sahip olan şehri bulmak için bir sorgu çalıştırabilir, ardından bu şehirden tüm müşterileri bulmak için sonucu başka bir sorguda kullanabilirsiniz:

// 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
            }
        }
    }
}

Sonucu önceki örneğin yarısı kadar sürede almak için iç içe yerleştirilmiş ifadeler içeren tek bir SQL sorgusu kullanın:

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
    }
}

SQL'de benzersizliği kontrol etme

Bir satırın, belirli bir sütun değeri tabloda benzersiz olmadığı sürece eklenmemesi gerekiyorsa bu benzersizliği sütun kısıtlaması olarak zorunlu kılmak daha verimli olabilir.

Aşağıdaki örnekte, eklenecek satırı doğrulamak için bir sorgu, eklemek için ise başka bir sorgu çalıştırılır:

// 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
    )
)

Kotlin'de benzersiz kısıtlamayı kontrol etmek yerine tabloyu tanımlarken SQL'de kontrol edebilirsiniz:

CREATE TABLE Customers(
  id INTEGER PRIMARY KEY,
  name TEXT,
  username TEXT UNIQUE
);

SQLite, aşağıdakilerle aynı işlemi yapar:

CREATE TABLE Customers(...);
CREATE UNIQUE INDEX CustomersUsername ON Customers(username);

Artık bir satır ekleyebilir ve kısıtlamayı SQLite'ın kontrol etmesine izin verebilirsiniz:

try {
    db.execSql(
        "INSERT INTO Customers VALUES (?, ?, ?)",
        arrayOf(customer.id.toString(), customer.name, customer.username)
    )
} catch(e: SQLiteConstraintException) {
    throw AddCustomerException(customer, e)
}

SQLite, birden çok sütun içeren benzersiz dizinleri destekler:

CREATE TABLE table(...);
CREATE UNIQUE INDEX unique_table ON table(column1, column2, ...);

SQLite, kısıtlamaları Kotlin koduna kıyasla daha hızlı ve daha az ek yükle doğrular. Uygulama kodu yerine SQLite kullanmak en iyi uygulamadır.

Tek bir işlemde birden fazla ekleme işlemini toplu olarak gerçekleştirme

Bir işlem, birden fazla işlemi yürütür. Bu da yalnızca verimliliği değil, doğruluğu da artırır. Veri tutarlılığını artırmak ve performansı hızlandırmak için eklemeleri toplu olarak yapabilirsiniz:

db.beginTransaction()
try {
    customers.forEach { customer ->
        db.execSql(
            "INSERT INTO Customers VALUES (?, ?, ?)",
            arrayOf(customer.id.toString(), customer.name, "customerValue")
        )
    }
} finally {
    db.endTransaction()
}

Sorun giderme araçlarını kullanma

SQLite, performansı ölçmenize yardımcı olmak için aşağıdaki sorun giderme araçlarını sağlar.

SQLite'ın etkileşimli istemini kullanma

Sorgu çalıştırmak ve öğrenmek için makinenizde SQLite'ı çalıştırın. Farklı Android platform sürümleri, SQLite'ın farklı düzeltmelerini kullanır. Android destekli bir cihazdaki motoru kullanmak için adb shell kullanın ve hedef cihazınızda sqlite3 komutunu çalıştırın.

SQLite'tan sorguların süresini ölçmesini isteyebilirsiniz:

sqlite> .timer on
sqlite> SELECT ...
Run Time: real ... user ... sys ...

EXPLAIN QUERY PLAN

SQLite'tan EXPLAIN QUERY PLAN kullanarak bir sorguyu nasıl yanıtlayacağını açıklamasını isteyebilirsiniz:

sqlite> EXPLAIN QUERY PLAN
SELECT id, name
FROM Customers
WHERE city = 'Paris';
QUERY PLAN
`--SCAN Customers

Önceki örnekte, Paris'teki tüm müşterileri bulmak için dizin olmadan tam tablo taraması yapılması gerekir. Buna doğrusal karmaşıklık denir. SQLite'ın tüm satırları okuması ve yalnızca Paris'teki müşterilerle eşleşen satırları tutması gerekir. Bu sorunu düzeltmek için dizin ekleyebilirsiniz:

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=?

Etkileşimli kabuğu kullanıyorsanız SQLite'tan her zaman sorgu planlarını açıklamasını isteyebilirsiniz:

sqlite> .eqp on

Daha fazla bilgi için Sorgu Planlama bölümüne bakın.

SQLite Analiz Aracı

SQLite, performansla ilgili sorunları gidermek için kullanılabilecek ek bilgileri boşaltmak üzere sqlite3_analyzer komut satırı arayüzünü (KSA) sunar. Yüklemek için SQLite İndirme Sayfası'nı ziyaret edin.

Bir veritabanı dosyasını hedef cihazdan iş istasyonunuza indirip analiz etmek için adb pull simgesini kullanabilirsiniz:

adb pull /data/data/<app_package_name>/databases/<db_name>.db

SQLite Browser

Ayrıca, SQLite Browser adlı GUI aracını SQLite İndirmeler sayfasından da yükleyebilirsiniz.

Android günlük kaydı

Android, SQLite sorgularının süresini ölçer ve bunları sizin için günlüğe kaydeder:

# Enable query time logging
$ adb shell setprop log.tag.SQLiteTime VERBOSE
# Disable query time logging
$ adb shell setprop log.tag.SQLiteTime ERROR

Perfetto izleme

Perfetto'yu yapılandırırken, tek tek sorgular için izlemeleri dahil etmek üzere aşağıdakileri ekleyebilirsiniz:

data_sources {
  config {
    name: "linux.ftrace"
    ftrace_config {
      atrace_categories: "database"
    }
  }
}

dumpsys meminfo

adb shell dumpsys meminfo <package-name>, SQLite belleğiyle ilgili bazı ayrıntılar da dahil olmak üzere uygulamanın bellek kullanımıyla ilgili istatistikleri yazdırır. Örneğin, bu, bir geliştiricinin cihazında adb shell dumpsys meminfo com.google.android.gms.persistent komutunun çıkışından alınmıştır:

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

DATABASES bölümünde şunları bulabilirsiniz:

  • pgsz: Bir veritabanı sayfasının boyutu (KB cinsinden).
  • dbsz: Veritabanının tamamının boyutu (sayfa olarak). Boyutu KB cinsinden almak için pgsz ile dbsz değerini çarpın.
  • Lookaside(b): Bağlantı başına SQLite lookaside arabelleğine ayrılan bellek (bayt cinsinden). Bunlar genellikle çok küçüktür.
  • cache hits: SQLite, veritabanı sayfalarının önbelleğini tutar. Bu, sayfa önbelleği isabetlerinin sayısıdır (sayım).
  • cache misses: Sayfa önbelleği isabet etmeme sayısı (sayım).
  • cache size: Önbellekteki sayfa sayısı (adet). Boyutu KB cinsinden almak için bu sayıyı pgsz ile çarpın.
  • Dbname: DB dosyasının yolu. Örneğimizde, aynı temel veritabanına birden fazla bağlantı olduğunu belirtmek için bazı veritabanlarının adlarına (1) veya başka bir sayı eklenmiştir. İstatistikler bağlantı bazında izlenir.

POOL STATS bölümünde şunları bulabilirsiniz:

  • cache hits: SQLite, hazırlanan ifadeleri önbelleğe alır ve SQL ifadelerini derlerken biraz çaba ve bellek tasarrufu sağlamak için sorguları çalıştırırken bunları yeniden kullanmaya çalışır. Bu, ifade önbelleği isabetlerinin sayısıdır.
  • cache misses: İfade önbelleği kaçırma sayısı (sayım).
  • cache size: Android 17'den itibaren bu, önbellekteki toplam hazırlanmış ifade sayısını listeler. Önceki sürümlerde bu değer, diğer iki sütunda listelenen isabet ve ıskalama sayılarının toplamına eşittir ve önbellek boyutunu temsil etmez.

Ek kaynaklar

İçeriği görüntüleme