Room Database Sorgu Optimizasyonu: @Query İpuçları ve Tuzakları
Room'da veri çekmek kolay görünse de yanlış bir @Query yazısı uygulamanızı yavaşlatabilir. Özellikle ilişkili tablolarla çalışırken performans düşüşü hızlı gelir.
En sık karşılaşılan sorun N+1 sorgusu. Bir liste döndüren sorgu yazıp sonra her satır için başka bir sorgu çalıştırmak veritabanını boşa yormak demek. Mesela kullanıcı listesi alıp her kullanıcının siparişlerini ayrı ayrı sorgularsanız, 100 kullanıcı için 101 sorgu çalışır.
1@Query("SELECT * FROM users")2fun getAllUsers(): List<User>34// Sonra kodda:5users.forEach { user ->6val orders = getUserOrders(user.id) // Her döngüde sorgu7}Bunun yerine ilişkili verileri tek sorguda çekin:
1@Query("""2SELECT u.*, o.* FROM users u3LEFT JOIN orders o ON u.id = o.user_id4""")5fun getUsersWithOrders(): List<UserWithOrders>UserWithOrders sınıfı Room'un ilişkiyi otomatik bağlamasını sağlar:
1data class UserWithOrders(2@Embedded val user: User,3@Relation(4parentColumn = "id",5entityColumn = "user_id"6)7val orders: List<Order>8)İkinci tuzak WHERE şartlarında indeks yok olan kolonları kullanmak. Binlerce satırda lineer arama yapılır ve sorgu yavaşlar. Sık filtrelenen alanlara @Index ekleyin:
1@Entity(indices = [Index(value = ["email"])])2data class User(3@PrimaryKey val id: Int,4val email: String,5val name: String6)Üçüncü hata: LIMIT ve OFFSET kötü kullanımı. Büyük OFFSET değerleri sorguyu yavaşlatır. 1000 satırı atlamak için 1000 satırı okuması gerekir. Sayfalama yaparken son id'yi referans alın:
1@Query("SELECT * FROM users WHERE id >:lastId ORDER BY id LIMIT:pageSize")2fun getUsersAfter(lastId: Int, pageSize: Int): List<User>Dördüncü: Gereksiz sütun çekme. 50 sütunlu tabloda sadece 2'sine ihtiyacsa hepsini çekmeyin:
1@Query("SELECT id, name FROM users WHERE email =:email")2fun getUserNameByEmail(email: String): UserNameOnly34data class UserNameOnly(5val id: Int,6val name: String7)Son ipucu: Kompleks sorgular için Flow veya LiveData kullanın. Veri değişirse otomatik güncellenir:
1@Query("SELECT * FROM users WHERE status =:status")2fun getActiveUsers(status: String): Flow<List<User>>Room sorguları compile-time'da kontrol edilir, bu yüzden yazım hatası yaparsanız derlenme aşamasında hata alırsınız. Bunu avantaja çevirin ve @Query'leri test edin. Sorgularınızı EXPLAIN PLAN ile analiz etmek de faydalı; hangi indekslerin kullanıldığını görürsünüz.
0 yorum