SQLite performansı için en iyi uygulamalar

Android, Android'de kullanıma sunulan SQLite için yerleşik destek daha verimli bir SQL veritabanıdır. Uygulamanızın performansını optimize etmek için Böylece, verileriniz büyüdükçe verilerinizin hızlı ve öngörülebilir hızda kalmasını sağlar. Bu en iyi uygulamaları kullanarak, yeniden oluşturması ve sorunlarını gidermesi zor olan performans sorunlarınla 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 işleyeceğiz. Veri tabanından okunan veri miktarını en aza indirin çünkü performansı etkileyebilir.

  • Çalışmayı SQLite Engine'e aktarın: Hesaplama, filtreleme ve sıralama işlemleri gerçekleştirin işlemleri gerçekleştirmelerini sağlar. SQLite'ın sorgu motorunu kullanarak performansı artırır.

  • Veritabanı şemasını değiştirme: Veritabanı şemanızı, SQLite'in etkili sorgu planları ve veri temsilleri oluşturmasına yardımcı olacak şekilde tasarlayın. Tabloları uygun şekilde dizine ekleme ve performansı artırmak için tablo yapılarını optimize edin.

Ayrıca, sorun giderme araçlarını kullanarak gereken alanları belirlemenize yardımcı olması için SQLite veritabanınızın optimize edebilirsiniz.

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

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

Veritabanınızı optimum şekilde yapılandırmak için bu bölümdeki adımları uygulayın. performansı hakkında daha fazla bilgi edinin.

Yazma Öncesi Günlük Kaydını Etkinleştir

SQLite, mutasyonları zaman zaman bir günlüğe ekleyerek uygular. veritabanına sıkıştırılır. Buna Write-Ahead Logging (Yazma Öncesi Günlük Kaydı) adı verilir. (WAL) ile değiştirin.

Etkinleştir DUVAR (ATTACH DATABASE kullanmıyorsanız)

Senkronizasyon modunu gevşetin

WAL kullanırken, her kaydetme işlemi için varsayılan olarak bir fsync verilir. Bu sayede verinin diske ulaşması anlamına gelir. Bu işlem, verilerin dayanıklılığını artırır ancak kaydeder.

SQLite'te senkron modunu kontrol etme seçeneği vardır. Şu durumda: WAL'yi etkinleştir, eşzamanlı modu NORMAL olarak ayarla:

Kotlin

db.execSQL("PRAGMA synchronous = NORMAL")

Java

db.execSQL("PRAGMA synchronous = NORMAL");

Bu ayarda, bir kaydetme işlemi, veriler diskte depolanmadan önce dönebilir. güç kesintisi veya çekirdek paniği gibi durumlarda cihazın kapanması kaydedilen veriler kaybolabilir. Ancak, günlük kaydı nedeniyle veritabanınız bozuk.

Yalnızca uygulamanız kilitlenirse verileriniz diske erişmeye devam eder. Çoğu uygulamada bu ayar, ayarı, herhangi 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ına bakalım. SQLite, verimli sorgu planları ve veriler oluşturur. Bu sayede, verileri daha hızlı almanıza yardımcı olur. Bu bölümde, tablo şemaları oluşturmayla ilgili en iyi uygulamalar yer almaktadır.

INTEGER PRIMARY KEY ürününü düşünün

Bu örnekte, bir tabloyu aşağıdaki gibi tanımlayıp 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 çıktısı aşağıdaki gibidir:

satır kimliği id ad şehir
1 456 Can Lennon Liverpool, İngiltere
2 123 Michael Jackson Gary, Indiana
3 789 Dolly Parton Sevier County, TN

rowid sütunu ekleme talimatını koruyan bir dizin. Sorguların rowid filtresi, hızlı bir B ağacı araması olarak uygulanır, ancak id filtresi yavaş bir tablo taramadır.

id tarihine kadar arama yapmayı planlıyorsanız, Depolama alanında daha az veri, toplamda ise daha az veri için rowid sütunu daha hızlı veritabanı:

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

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

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

rowid sütununu depolamanız gerekmediğinden, id sorguları hızlıdır. Not Böylece, tablonun artık kampanya siparişi yerine id temel alınarak sıralandığı gösteriliyor.

Dizinleri kullanarak sorguları hızlandırma

SQLite, sorguları hızlandırmak için dizinler kullanır. Filtreleme sırasında (WHERE), sıralama yaparken (ORDER BY) veya bir sütun toplanıyorsa (GROUP BY), tablonun sütun için bir dizini varsa sorgu hızlandırıldı.

Yukarıdaki örnekte, city ölçütüne göre 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);

Bir dizin, ek bir tablo olarak uygulanır. Bu dizin, dizin sütununa göre sıralanır ve rowid ile eşlendi:

şehir satır kimliği
Gary, Indiana 2
Liverpool, İngiltere 1
Sevier County, TN 3

city sütunu artık hem orijinal tabloda hem de dizinde bulunduğundan, sütunun depolama maliyetinin iki katına çıktığını unutmayın. ek depolama alanı maliyeti, daha hızlı sorguların yararınadır. Ancak, ödeme yaparken kullanmadığınız bir dizini saklamayın. depolama maliyeti oluşturmaya devam eder.

Çok sütunlu dizinler oluşturma

Sorgularınız birden çok sütunu birleştiriyorsa, çok sütunlu dizinleri kullanabilirsiniz. Ayrıca, bir dış sütunda da bir dizin kullanabilirsiniz ve iç aramanın doğrusal tarama olarak yapılmasını sağlayın.

Örneğin, aşağıdaki sorgu verildiğinde:

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

Çok sütunlu bir dizinle sorguyu aşağıdaki sırayla hızlandırabilirsiniz: sorguda belirtildiği gibi:

CREATE INDEX city_name_index ON Customers(city, name);

Ancak yalnızca city üzerinde bir dizininiz varsa dış sipariş yine de hızlandırılır. İç sipariş ise doğrusal tarama gerektirir.

Bu, önekli sorgularda da çalışır. Örneğin, ON Customers (city, name); filtreleme, sıralama ve gruplandırmayı da hızlandırır city değerine göre; çünkü çok sütunlu bir dizine ait dizin tablosu belirli bir sırada gösterir.

WITHOUT ROWID ürününü düşünün

Varsayılan olarak SQLite, tablonuz için bir rowid sütunu oluşturur. Burada rowid, varsayılan olarak bir dolaylı INTEGER PRIMARY KEY AUTOINCREMENT. Varsayılan INTEGER PRIMARY KEY ise bu sütun rowid için takma ad olur.

INTEGER dışında bir birincil anahtarı veya sütunlardan oluşan bir karma anahtarı olan tablolar için WITHOUT ROWID'i kullanın.

Küçük verileri BLOB, büyük verileri ise dosya olarak depolayın

Bir satırla ilişkilendirmek istediğiniz büyük veriler (ör. bir resmin küçük resmi veya bir kişinin fotoğrafı) varsa verileri bir BLOB sütununda ya da dosyada saklayabilir ve ardından dosya yolunu sütunda saklayabilirsiniz.

Dosyalar genellikle 4 KB'lık artışlarla yuvarlanır. Çok küçük dosyalar için çok büyükse, yuvarlama hatasını büyük bir bölmede BLOB olarak veritabanını kullanabilirsiniz. SQLite, dosya sistemi çağrılarını en aza indirir ve temel dosya sistemi bazı durumlarda kullanabilirsiniz.

Sorgu performansını iyileştirme

Şu en iyi uygulamaları izleyerek SQLite'ta sorgu performansını artırmak için ve işlem verimliliğini en üst düzeye çıkarıyor.

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

Filtreler, belirli kriterler belirleyerek sonuçlarınızı daraltmanıza olanak tanır. (ör. tarih aralığı, konum veya ad) Sınırlar, sayıyı kontrol etmenize olanak tanır gösterilen sonuçlar:

Kotlin

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

Java

try (Cursor cursor = db.rawQuery("""
    SELECT name
    FROM Customers
    LIMIT 10;
    """, null)) {
  while (cursor.moveToNext()) {
    ...
  }
}

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

Gereksiz sütunlar seçmekten kaçının, aksi takdirde sorgularınızı yavaşlatabilir ve kaynaklarınızı israfa uğratabilir. Bunun yerine yalnızca sütunları seçin için de geçerli.

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

Kotlin

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

Java

// This is not the most efficient way of doing this.
// See the following example for a better approach.

try (Cursor cursor = db.rawQuery("""
    SELECT id, name, phone
    FROM customers;
    """, null)) {
  while (cursor.moveToNext()) {
    String name = cursor.getString(1);
    ...
  }
}

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

Kotlin

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

Java

try (Cursor cursor = db.rawQuery("""
    SELECT name
    FROM Customers;
    """, null)) {
  while (cursor.moveToNext()) {
    String name = cursor.getString(0);
    ...
  }
}

Sorguları Dize birleştirmeyle değil, SQL Kartları ile parametrelere dönüştürün

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

Kotlin

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

Java

@Nullable
public String getNameById(long id) {
  try (Cursor cursor = db.rawQuery(
      "SELECT name FROM customers WHERE id=" + id, null)) {
    if (cursor.moveToFirst()) {
      return cursor.getString(0);
    } else {
      return null;
    }
  }
}

Önceki kodda, her sorgu farklı bir dize oluşturur. Bu nedenle, , ekstre önbelleğinden yararlanmaz. Her çağrıda derleme için SQLite gerekir çalışmasını sağlamalısınız. Bunun yerine, id bağımsız değişkenini bir parametre ile değiştirebilir ve değeri selectionArgs ile bağlayabilirsiniz:

Kotlin

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

Java

@Nullable
public String getNameById(long id) {
  try (Cursor cursor = db.rawQuery("""
          SELECT name
          FROM customers
          WHERE id=?
      """, new String[] {String.valueOf(id)})) {
    if (cursor.moveToFirst()) {
      return cursor.getString(0);
    } else {
      return null;
    }
  }
}

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

Kodda değil, SQL'de yineleme

Programatik yerine, hedeflenen tüm sonuçları döndüren tek bir sorgu kullan Bağımsız sonuçlar döndürmek için SQL sorgularında döngü yineleme. 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şlenecek veri miktarını azaltarak sorgularınızın performansını artırabilir. Örneğin, bir sütundan yalnızca benzersiz değerleri döndürmek için DISTINCT işlevini kullanın:

Kotlin

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

Java

try (Cursor cursor = db.rawQuery("""
    SELECT DISTINCT name
    FROM Customers;
    """, null)) {
  while (cursor.moveToNext()) {
    // Only iterate over distinct names in Java
    ...
  }
}

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

Satır verileri içermeyen birleştirilmiş 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:

Kotlin

// 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
        ...
    } else {
        // No customers from Paris
        ...
}

Java

// This is not the most efficient way of doing this.
// See the following example for a better approach.

try (Cursor cursor = db.rawQuery("""
    SELECT id, name
    FROM Customers
    WHERE city = 'Paris';
    """, null)) {
  if (cursor.moveToFirst()) {
    // At least one customer from Paris
    ...
  } else {
    // No customers from Paris
    ...
  }
}

Yalnızca ilk satırı almak için EXISTS() kullanabilirsiniz. Eşleşen bir satır yoksa 0, bir veya daha fazla satır eşleşirse 1 döndürülür:

Kotlin

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
        ...
    } else {
        // No customers from Paris
        ...
    }
}

Java

try (Cursor cursor = db.rawQuery("""
    SELECT EXISTS (
      SELECT null
      FROM Customers
      WHERE city = 'Paris'
    );
    """, null)) {
  if (cursor.moveToFirst() && cursor.getInt(0) == 1) {
    // At least one customer from Paris
    ...
  } else {
    // No customers from Paris
    ...
  }
}

SQLite toplama özelliğini kullanma işlevleriyle ilgili daha fazla bilgi edinin. kod:

  • COUNT: Bir sütunda kaç satır olduğunu sayar.
  • SUM: Bir sütundaki tüm sayısal değerleri ekler.
  • MIN veya MAX: En düşük veya en yüksek değeri belirler. Sayısal sütunlar, DATE türleri ve metin türleri için çalışır.
  • AVG: Ortalama sayısal değeri 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:

Kotlin

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

Java

// This is not the most efficient way of doing this.
// See the following example for a better approach.

try (Cursor cursor = db.rawQuery("""
    SELECT id
    FROM Customers;
    """, null)) {
  int count = cursor.getCount();
  ...
}

Ancak COUNT() kullanıldığında, veritabanı yalnızca sayı:

Kotlin

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

Java

try (Cursor cursor = db.rawQuery("""
    SELECT COUNT(*)
    FROM Customers;
    """, null)) {
  cursor.moveToFirst();
  int count = cursor.getInt(0);
  ...
}

Kod yerine Nest sorguları

SQL composable'dır ve alt sorguları, birleştirmeleri ve yabancı anahtar kısıtlamalarını destekler. Bir sorgunun sonucunu, uygulamaya gitmeden başka bir sorguda kullanabilirsiniz. girin. Bu sayede SQLite'dan veri kopyalama ihtiyacı azalır ve veritabanı Google Analytics 4.0'dan ibarettir.

Aşağıdaki örnekte, şehirdeki en büyük şehirleri bulmak için sonra bu sonucu başka bir sorguda kullanarak şu şehir:

Kotlin

// 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()) {
                ...
            }
        }
    }
}

Java

// This is not the most efficient way of doing this.
// See the following example for a better approach.

try (Cursor cursor = db.rawQuery("""
    SELECT city
    FROM Customers
    GROUP BY city
    ORDER BY COUNT(*) DESC
    LIMIT 1;
    """, null)) {
  if (cursor.moveToFirst()) {
    String topCity = cursor.getString(0);
    try (Cursor innerCursor = db.rawQuery("""
        SELECT name, city
        FROM Customers
        WHERE city = ?;
        """, new String[] {topCity})) {
        while (innerCursor.moveToNext()) {
          ...
        }
    }
  }
}

Önceki örneğin yarısında sonucu almak için tek bir SQL kullanın iç içe yerleştirilmiş ifadeler içeren bir sorgu:

Kotlin

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()) {
        ...
    }
}

Java

try (Cursor cursor = db.rawQuery("""
    SELECT name, city
    FROM Customers
    WHERE city IN (
      SELECT city
      FROM Customers
      GROUP BY city
      ORDER BY COUNT(*) DESC
      LIMIT 1
    );
    """, null)) {
  while(cursor.moveToNext()) {
    ...
  }
}

SQL'deki benzersizliği kontrol edin

Belirli bir sütun değerinin bir sütun haline getirirse, bu benzersizliği bir sütun olarak uygulamak daha verimli olabilir. kısıtlayın.

Aşağıdaki örnekte, oluşturulacak satırı doğrulamak için bir sorgu çalıştırılmıştır eklendi:

Kotlin

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

Java

// This is not the most efficient way of doing this.
// See the following example for a better approach.

try (Cursor cursor = db.rawQuery("""
    SELECT EXISTS (
      SELECT null
      FROM customers
      WHERE username = ?
    );
    """, new String[] { customer.username })) {
  if (cursor.moveToFirst() && cursor.getInt(0) == 1) {
    throw new AddCustomerException(customer);
  }
}
db.execSQL(
    "INSERT INTO customers VALUES (?, ?, ?)",
    new String[] {
      String.valueOf(customer.id),
      customer.name,
      customer.username,
    });

Kotlin veya Java'daki benzersiz kısıtlamayı kontrol etmek yerine, Tabloyu tanımladığınızda SQL:

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

SQLite aşağıdakilerle aynı işlemleri yapar:

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

Şimdi bir satır ekleyip SQLite'ın kısıtlamayı kontrol etmesini sağlayabilirsiniz:

Kotlin

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

Java

try {
  db.execSQL(
      "INSERT INTO Customers VALUES (?, ?, ?)",
      new String[] {
        String.valueOf(customer.id),
        customer.name,
        customer.username,
      });
} catch (SQLiteConstraintException e) {
  throw new AddCustomerException(customer, e);
}

SQLite, birden çok sütunlu benzersiz dizinleri destekler:

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

SQLite, kısıtlamaları Kotlin veya Java'ya göre daha hızlı ve daha az ek yük ile doğrular girin. Uygulama kodu yerine SQLite kullanmak en iyi uygulamalardan biridir.

Tek bir işlemde birden çok ekleme işlemi yapma

Bir işlem birden fazla işlem gerçekleştirir, bu da hem de doğruluğu kapsar. Veri tutarlılığını artırmak ve performansı artırmak istiyorsanız toplu eklemeler yapabilirsiniz:

Kotlin

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

Java

db.beginTransaction();
try {
  for (customer : Customers) {
    db.execSQL(
        "INSERT INTO Customers VALUES (?, ?, ...)",
        new String[] {
          String.valueOf(customer.id),
          customer.name,
          ...
        });
  }
} finally {
  db.endTransaction()
}

Sorun giderme araçlarını kullanma

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

SQLite'in etkileşimli istemlerini kullanma

Sorgu çalıştırmak ve bilgi edinmek için makinenizde SQLite çalıştırın. Farklı Android platform sürümlerinde SQLite'ın farklı revizyonları kullanılır. Android destekli bir cihazdakiyle aynı motoru kullanmak için adb shell'ü kullanın ve hedef cihazınızda sqlite3'ü çalıştırın.

SQLite'tan sorguları zamanlamasını isteyebilirsiniz:

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

EXPLAIN QUERY PLAN

SQLite'tan bir sorguyu EXPLAIN QUERY PLAN:

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

Önceki örnekte, tüm sonuçları bulmak için dizin olmadan tam bir tablo taraması yapılmalıdır. bir teklif eklediğinizden emin olun. Buna doğrusal karmaşıklık denir. SQLite'ın okuması gerekiyor tüm satırları kaldırın ve yalnızca Paris'teki müşterilerle eşleşen satırları tutun. 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'ten sorgu planlarını her zaman açıklamasını isteyebilirsiniz:

sqlite> .eqp on

Daha fazla bilgi için bkz. Sorgu Planlama.

SQLite Analiz Aracı

SQLite, sqlite3_analyzer komut satırı arayüzü (KSA) kullanarak, performans sorunlarını gidermeye yardımcı olur. Yüklemek için SQLite İndirme Sayfası.

Bir hedef cihazdan cihazınıza veritabanı indirmek için adb pull kullanabilirsiniz analiz için iş istasyonu:

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

SQLite Tarayıcı

GUI aracını da yükleyebilirsiniz SQLite üzerinde SQLite Tarayıcı İndirilenler sayfası.

Android günlük kaydı

Android, SQLite sorgularını zamanlayıp 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 tracing

### Perfetto tracing {:#perfetto-tracing}

When [configuring Perfetto](https://perfetto.dev/docs/concepts/config), you may
add the following to include tracks for individual queries:

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