Хүрээн дэх каскад устгалт удаан хугацааны турш хэрхэн ялсан тухай үлгэр

Бүх хэрэглэгчид гар утасны програмын хурдан эхлүүлэх, хариу үйлдэл үзүүлэх UI ашигладаг. Хэрэв програмыг эхлүүлэхэд удаан хугацаа шаардагдах юм бол хэрэглэгч гунигтай, уурлаж эхэлдэг. Та хэрэглэгчийн туршлагыг амархан сүйтгэх эсвэл хэрэглэгчийг програмыг ашиглаж эхлэхээс өмнө бүрмөсөн алдах боломжтой.

Додо пицца програмыг эхлүүлэхэд дунджаар 3 секунд зарцуулдаг бол зарим "азтай" аппликейшнд 15-20 секунд зарцуулдгийг бид олж мэдсэн.

Зүсэлтийн доор аз жаргалтай төгсгөлтэй түүх байна: Realm мэдээллийн сангийн өсөлт, санах ойн алдагдал, бид үүрлэсэн объектуудыг хэрхэн хуримтлуулж, дараа нь өөрсдийгөө нэгтгэж, бүгдийг зассан тухай.

Хүрээн дэх каскад устгалт удаан хугацааны турш хэрхэн ялсан тухай үлгэр

Хүрээн дэх каскад устгалт удаан хугацааны турш хэрхэн ялсан тухай үлгэр
Нийтлэлийн зохиогч: Максим Качинкин — Dodo Pizza дахь Android хөгжүүлэгч.

Програмын дүрс дээр дарснаас хойш эхний үйл ажиллагааны onResume() хүртэл гурван секунд бол хязгааргүй юм. Мөн зарим хэрэглэгчдийн хувьд эхлүүлэх хугацаа 15-20 секунд хүрдэг. Энэ нь яаж боломжтой юм бэ?

Унших завгүй хүмүүст зориулсан маш товч тойм
Манай Realm мэдээллийн сан эцэс төгсгөлгүй нэмэгдэв. Зарим үүрлэсэн объектууд устгагдаагүй боловч байнга хуримтлагдаж байсан. Програмыг эхлүүлэх хугацаа аажмаар нэмэгдэв. Дараа нь бид үүнийг засч, эхлүүлэх хугацаа нь зорилтот түвшинд хүрсэн - энэ нь 1 секундээс бага болж, цаашид нэмэгдэхээ больсон. Нийтлэлд нөхцөл байдлын дүн шинжилгээ, хурдан, энгийн гэсэн хоёр шийдлийг багтаасан болно.

Асуудлыг хайх, дүн шинжилгээ хийх

Өнөөдөр аливаа гар утасны програм хурдан ажиллаж, хариу үйлдэл үзүүлэх ёстой. Гэхдээ энэ нь зөвхөн гар утасны програмын тухай биш юм. Хэрэглэгчийн үйлчилгээ, компанитай харилцах туршлага нь нарийн төвөгтэй зүйл юм. Жишээлбэл, манайд хүргэх хурд нь пиццаны үйлчилгээний гол үзүүлэлтүүдийн нэг юм. Хүргэлт хурдан байвал пицца халуун байх бөгөөд одоо идэхийг хүссэн үйлчлүүлэгч удаан хүлээх шаардлагагүй болно. Аппликейшний хувьд эргээд хурдан үйлчилгээний мэдрэмжийг бий болгох нь чухал, учир нь програмыг эхлүүлэхэд ердөө 20 секунд шаардлагатай бол та пиццагаа хэр удаан хүлээх вэ?

Эхлээд бид өөрсдөө заримдаа програмыг эхлүүлэхэд хэдхэн секунд зарцуулдаг гэсэн асуудалтай тулгардаг байсан бөгөөд дараа нь бусад хамт ажиллагсдаас хэр удаан хугацаа шаардагддаг тухай гомдлыг сонсож эхэлсэн. Гэвч бид энэ байдлыг байнга давтаж чадаагүй.

Хэр удаан вэ? дагуу Google-ийн баримт бичиг, хэрэв програмыг хүйтэн эхлүүлэхэд 5 секундээс бага хугацаа шаардагддаг бол үүнийг "хэвийн юм шиг" гэж үзнэ. Dodo Pizza Android програмыг эхлүүлсэн (Firebase хэмжүүрийн дагуу _аппыг эхлүүлэх) цагт хүйтэн эхлэл Дунджаар 3 секундэд - "Гайхалтай биш, аймшигтай биш" гэж тэдний хэлснээр.

Гэвч дараа нь уг програмыг эхлүүлэхэд маш, маш, маш удаан хугацаа шаардагддаг гэсэн гомдол гарч эхэлсэн! Эхлээд бид "маш, маш, маш урт" гэж юу болохыг хэмжихээр шийдсэн. Үүний тулд бид Firebase мөрийг ашигласан Апп эхлэлийн ул мөр.

Хүрээн дэх каскад устгалт удаан хугацааны турш хэрхэн ялсан тухай үлгэр

Энэхүү стандарт мөр нь хэрэглэгч аппликешныг нээх мөчөөс эхний үйлдлийн onResume()-г гүйцэтгэх хүртэлх хугацааг хэмждэг. Firebase консол дээр энэ хэмжигдэхүүнийг _app_start гэж нэрлэдэг. Энэ нь:

  • 95-аас дээш хувьтай хэрэглэгчдийн хувьд эхлүүлэх хугацаа нь бараг 20 секунд (зарим нь бүр ч урт) байдаг ч дундаж хүйтэн эхлүүлэх хугацаа 5 секундээс бага байдаг.
  • Эхлэх хугацаа нь тогтмол утга биш, харин цаг хугацааны явцад өсдөг. Гэхдээ заримдаа дусал байдаг. Шинжилгээний цар хүрээг 90 хоног болгон нэмэгдүүлэхэд бид энэ загварыг олж мэдсэн.

Хүрээн дэх каскад устгалт удаан хугацааны турш хэрхэн ялсан тухай үлгэр

Хоёр бодол толгойд орж ирэв:

  1. Ямар нэг зүйл гоожиж байна.
  2. Энэ "ямар нэгэн зүйл" гарсны дараа дахин тохируулагдаж, дараа нь дахин гоожиж байна.

"Мэдээллийн сантай холбоотой байж магадгүй" гэж бид бодсон бөгөөд бидний зөв байсан. Нэгдүгээрт, бид мэдээллийн санг кэш болгон ашигладаг бөгөөд шилжих явцад бид үүнийг арилгадаг. Хоёрдугаарт, програм эхлэхэд мэдээллийн сан ачаалагддаг. Бүх зүйл хоорондоо зохицдог.

Realm мэдээллийн санд юу нь буруу байна

Бид анхны суулгацаас эхлээд идэвхтэй ашиглах явцад мэдээллийн сангийн агуулга програмын ашиглалтын хугацаанд хэрхэн өөрчлөгдөж байгааг шалгаж эхэлсэн. Та Realm мэдээллийн сангийн агуулгыг үзэх боломжтой Стето эсвэл файлыг нээснээр илүү дэлгэрэнгүй, тодорхой болно Realm Studio. АХБ-аар дамжуулан мэдээллийн сангийн агуулгыг үзэхийн тулд Realm мэдээллийн сангийн файлыг хуулна уу:

adb exec-out run-as ${PACKAGE_NAME} cat files/${DB_NAME}

Өгөгдлийн сангийн агуулгыг өөр өөр цаг үед судалж үзээд тодорхой төрлийн объектын тоо байнга нэмэгдэж байгааг олж мэдсэн.

Хүрээн дэх каскад устгалт удаан хугацааны турш хэрхэн ялсан тухай үлгэр
Зураг дээр Realm Studio-ийн хоёр файлд зориулсан фрагментийг харуулж байна: зүүн талд - суулгасны дараа хэсэг хугацааны дараа програмын суурь, баруун талд - идэвхтэй ашигласны дараа. Энэ нь объектын тоо байгааг харж болно ImageEntity и MoneyType ихээхэн өссөн (дэлгэцийн агшинд төрөл бүрийн объектын тоог харуулав).

Өгөгдлийн сангийн өсөлт ба эхлүүлэх цаг хоорондын хамаарал

Мэдээллийн сангийн хяналтгүй өсөлт маш муу байна. Гэхдээ энэ нь програмыг эхлүүлэх хугацаанд хэрхэн нөлөөлөх вэ? ActivityManager-ээр дамжуулан үүнийг хэмжихэд маш хялбар байдаг. Android 4.4-с хойш logcat нь логийг Displayed тэмдэгт болон цагийг харуулдаг. Энэ хугацаа нь аппликешныг эхлүүлсэн цагаас эхлэн үйл ажиллагааны дүрслэл дуусах хүртэлх хугацаатай тэнцүү байна. Энэ хугацаанд дараахь үйл явдлууд тохиолддог.

  • Процессыг эхлүүлэх.
  • Объектуудыг эхлүүлэх.
  • Үйл ажиллагааг бий болгох, эхлүүлэх.
  • Байрлал үүсгэх.
  • Хэрэглээний дүрслэл.

Бидэнд тохирсон. Хэрэв та АХБ-ыг -S ба -W тугуудаар ажиллуулж байгаа бол эхлүүлэх хугацаатай өргөтгөсөн гаралтыг авах боломжтой.

adb shell am start -S -W ru.dodopizza.app/.MainActivity -c android.intent.category.LAUNCHER -a android.intent.action.MAIN

Хэрэв та тэндээс барьж авбал grep -i WaitTime Цаг хугацаа өнгөрөхөд та энэ хэмжүүрийн цуглуулгыг автоматжуулж, үр дүнг нүдээр харах боломжтой. Доорх график нь програмыг эхлүүлэх хугацаа нь програмын хүйтэн эхлэх тооноос хамаарлыг харуулж байна.

Хүрээн дэх каскад устгалт удаан хугацааны турш хэрхэн ялсан тухай үлгэр

Үүний зэрэгцээ мэдээллийн сангийн хэмжээ, өсөлтийн хоорондын хамаарлын ижил шинж чанар байсан бөгөөд энэ нь 4 МБ-аас 15 МБ хүртэл өссөн байна. Нийтдээ цаг хугацаа өнгөрөхөд (хүйтэн эхлэх тусам) програмыг эхлүүлэх хугацаа болон мэдээллийн сангийн хэмжээ хоёулаа нэмэгдсэн нь харагдаж байна. Бидний гарт таамаглал бий. Одоо зөвхөн хамаарлыг батлах л үлдлээ. Тиймээс бид "алдсан" -ыг арилгахаар шийдсэн бөгөөд энэ нь хөөргөлтийг хурдасгах эсэхийг харахаар шийдсэн.

Өгөгдлийн сангийн эцэс төгсгөлгүй өсөлтийн шалтгаанууд

"Нэвчилт" -ийг арилгахын өмнө тэд яагаад анх гарч ирснийг ойлгох нь зүйтэй. Үүнийг хийхийн тулд Хүрээ гэж юу болохыг санацгаая.

Realm нь харилцаа холбоогүй мэдээллийн сан юм. Энэ нь Андройд дээрх хэдэн ORM харилцааны мэдээллийн баазыг дүрсэлсэнтэй ижил аргаар объектуудын хоорондын харилцааг дүрслэх боломжийг танд олгоно. Үүний зэрэгцээ Realm нь объектуудыг хамгийн бага өөрчлөлт, зураглалтайгаар санах ойд шууд хадгалдаг. Энэ нь дискнээс өгөгдлийг маш хурдан унших боломжийг олгодог бөгөөд энэ нь Realm-ийн хүч чадал, яагаад үүнийг хайрладаг вэ.

(Энэ нийтлэлийн зорилгын үүднээс энэ тайлбар бидэнд хангалттай байх болно. Та Хүрээний талаар илүү ихийг уншиж болно баримт бичиг эсвэл тэдний дотор академи).

Олон хөгжүүлэгчид харилцааны өгөгдлийн сантай илүү их ажиллахад дассан байдаг (жишээлбэл, SQL бүхий ORM мэдээллийн баазууд). Мөн өгөгдлийг шат дараалан устгах гэх мэт зүйлс ихэвчлэн өгөгдсөн мэт санагддаг. Гэхдээ Realm-д биш.

Дашрамд хэлэхэд, каскад устгах функцийг удаан хугацаанд асууж байсан. Энэ засвар и өөр, түүнтэй холбоотой талаар идэвхтэй хэлэлцсэн. Удахгүй бүтнэ гэсэн мэдрэмж төрж байсан. Гэвч дараа нь бүх зүйл хүчтэй, сул холбоосуудын танилцуулга болж хувирсан бөгөөд энэ нь энэ асуудлыг автоматаар шийдэх болно. Энэ ажилд нэлээд эрч хүчтэй, идэвхтэй байсан татах хүсэлт, дотоод хүндрэлээс болж одоогоор түр зогсоод байна.

Өгөгдлийн шаталсан устгалгүйгээр алдагдсан

Хэрэв та байхгүй шаталсан устгалд найдаж байгаа бол өгөгдөл яг яаж алдагдах вэ? Хэрэв та Realm объектуудыг оруулсан бол тэдгээрийг устгах ёстой.
Бодит (бараг) жишээг харцгаая. Бидэнд объект байна CartItemEntity:

@RealmClass
class CartItemEntity(
 @PrimaryKey
 override var id: String? = null,
 ...
 var name: String = "",
 var description: String = "",
 var image: ImageEntity? = null,
 var category: String = MENU_CATEGORY_UNKNOWN_ID,
 var customizationEntity: CustomizationEntity? = null,
 var cartComboProducts: RealmList<CartProductEntity> = RealmList(),
 ...
) : RealmObject()

Сагсанд байгаа бүтээгдэхүүн нь зураг зэрэг өөр өөр талбаруудтай ImageEntity, захиалгат найрлага CustomizationEntity. Мөн сагсанд байгаа бүтээгдэхүүн нь өөрийн гэсэн багц бүтээгдэхүүнтэй хослуулан байж болно RealmList (CartProductEntity). Бүртгэгдсэн бүх талбарууд нь Realm объектууд юм. Хэрэв бид ижил ID-тай шинэ объект (copyToRealm() / copyToRealmOrUpdate()) оруулбал энэ объект бүрэн дарж бичигдэх болно. Гэхдээ бүх дотоод объектууд (зураг, customizationEntity болон cartComboProducts) эцэг эхтэй холбоо тасарч, мэдээллийн санд үлдэх болно.

Тэдэнтэй холбоо тасарсан тул бид тэдгээрийг уншихгүй, устгахаа больсон (хэрэв бид тэдгээрт шууд хандах эсвэл "хүснэгтийг" бүхэлд нь арилгахаас бусад тохиолдолд). Бид үүнийг "санах ойн алдагдал" гэж нэрлэсэн.

Бид Realm-тэй ажиллахдаа ийм үйлдлээс өмнө бүх элементүүдийг нарийвчлан судалж, бүгдийг устгах ёстой. Үүнийг жишээлбэл, дараах байдлаар хийж болно.

val entity = realm.where(CartItemEntity::class.java).equalTo("id", id).findFirst()
if (first != null) {
 deleteFromRealm(first.image)
 deleteFromRealm(first.customizationEntity)
 for(cartProductEntity in first.cartComboProducts) {
   deleteFromRealm(cartProductEntity)
 }
 first.deleteFromRealm()
}
// и потом уже сохраняем

Хэрэв та үүнийг хийвэл бүх зүйл хүссэнээрээ ажиллах болно. Энэ жишээнд бид image, customizationEntity болон cartComboProducts дотор өөр ямар ч үүрлэсэн Realm объект байхгүй гэж үзэж байгаа тул өөр үүрлэсэн гогцоо, устгах зүйл байхгүй.

"Шуурхай" шийдэл

Бидний хийхээр шийдсэн хамгийн эхний зүйл бол хамгийн хурдан өсөн нэмэгдэж буй объектуудыг цэвэрлэж, үр дүнг нь шалгах нь бидний анхны асуудлыг шийдэж чадах эсэхийг шалгах явдал байв. Нэгдүгээрт, хамгийн энгийн бөгөөд ойлгомжтой шийдлийг гаргасан, тухайлбал: объект бүр хүүхдүүдээ зайлуулах үүрэгтэй байх ёстой. Үүнийг хийхийн тулд бид өөрийн дотоод хүрээний объектуудын жагсаалтыг буцаадаг интерфейсийг нэвтрүүлсэн:

interface NestedEntityAware {
 fun getNestedEntities(): Collection<RealmObject?>
}

Мөн бид үүнийг өөрийн хүрээний объектуудад хэрэгжүүлсэн:

@RealmClass
class DataPizzeriaEntity(
 @PrimaryKey
 var id: String? = null,
 var name: String? = null,
 var coordinates: CoordinatesEntity? = null,
 var deliverySchedule: ScheduleEntity? = null,
 var restaurantSchedule: ScheduleEntity? = null,
 ...
) : RealmObject(), NestedEntityAware {

 override fun getNestedEntities(): Collection<RealmObject?> {
   return listOf(
       coordinates,
       deliverySchedule,
       restaurantSchedule
   )
 }
}

В getNestedEntities Бид бүх хүүхдийг хавтгай жагсаалт болгон буцааж өгдөг. Мөн хүүхэд объект бүр NestedEntityAware интерфэйсийг хэрэгжүүлэх боломжтой бөгөөд энэ нь устгах дотоод Realm объектуудтай болохыг харуулж байна. ScheduleEntity:

@RealmClass
class ScheduleEntity(
 var monday: DayOfWeekEntity? = null,
 var tuesday: DayOfWeekEntity? = null,
 var wednesday: DayOfWeekEntity? = null,
 var thursday: DayOfWeekEntity? = null,
 var friday: DayOfWeekEntity? = null,
 var saturday: DayOfWeekEntity? = null,
 var sunday: DayOfWeekEntity? = null
) : RealmObject(), NestedEntityAware {

 override fun getNestedEntities(): Collection<RealmObject?> {
   return listOf(
       monday, tuesday, wednesday, thursday, friday, saturday, sunday
   )
 }
}

Гэх мэтээр объектуудын үүрийг давтаж болно.

Дараа нь бид бүх үүрлэсэн объектуудыг рекурсив устгах аргыг бичнэ. Арга (өргөтгөл хэлбэрээр хийсэн) deleteAllNestedEntities бүх дээд түвшний объект, аргыг авдаг deleteNestedRecursively NestedEntityAware интерфэйсийг ашиглан бүх үүрлэсэн объектуудыг давталттайгаар устгадаг:

fun <T> Realm.deleteAllNestedEntities(entities: Collection<T>,
 entityClass: Class<out RealmObject>,
 idMapper: (T) -> String,
 idFieldName : String = "id"
 ) {

 val existedObjects = where(entityClass)
     .`in`(idFieldName, entities.map(idMapper).toTypedArray())
     .findAll()

 deleteNestedRecursively(existedObjects)
}

private fun Realm.deleteNestedRecursively(entities: Collection<RealmObject?>) {
 for(entity in entities) {
   entity?.let { realmObject ->
     if (realmObject is NestedEntityAware) {
       deleteNestedRecursively((realmObject as NestedEntityAware).getNestedEntities())
     }
     realmObject.deleteFromRealm()
   }
 }
}

Бид үүнийг хамгийн хурдан өсөн нэмэгдэж буй объектуудтай хийж, юу болсныг шалгасан.

Хүрээн дэх каскад устгалт удаан хугацааны турш хэрхэн ялсан тухай үлгэр

Үүний үр дүнд бидний энэ уусмалаар бүрхсэн объектууд ургахаа больсон. Мөн суурийн ерөнхий өсөлт удааширсан боловч зогссонгүй.

"Хэвийн" шийдэл

Хэдийгээр суурь нь удаанаар ургаж эхэлсэн ч өссөөр байв. Тиймээс бид цаашаа хайж эхлэв. Манай төсөл Realm дахь өгөгдлийн кэшийг маш идэвхтэй ашигладаг. Тиймээс, объект бүрийн хувьд бүх үүрлэсэн объектыг бичих нь маш их хөдөлмөр шаарддаг бөгөөд алдаа гарах эрсдэл нэмэгддэг, учир нь та кодыг өөрчлөхдөө объектуудыг зааж өгөхөө мартаж болно.

Би интерфэйс ашигладаггүй, гэхдээ бүх зүйл өөрөө ажилладаг эсэхийг шалгахыг хүссэн.

Аливаа зүйлийг бие даан ажиллахыг хүсвэл бид тусгалыг ашиглах ёстой. Үүнийг хийхийн тулд бид ангийн талбар бүрийг үзэж, энэ нь Realm объект эсвэл объектын жагсаалт эсэхийг шалгаж болно.

RealmModel::class.java.isAssignableFrom(field.type)

RealmList::class.java.isAssignableFrom(field.type)

Хэрэв талбар нь RealmModel эсвэл RealmList бол энэ талбарын объектыг үүрлэсэн объектуудын жагсаалтад нэмнэ үү. Бүх зүйл дээр дурдсантай яг адилхан, зөвхөн энд үүнийг өөрөө хийх болно. Каскад устгах арга нь өөрөө маш энгийн бөгөөд дараах байдалтай байна.

fun <T : Any> Realm.cascadeDelete(entities: Collection<T?>) {
 if(entities.isEmpty()) {
   return
 }

 entities.filterNotNull().let { notNullEntities ->
   notNullEntities
       .filterRealmObject()
       .flatMap { realmObject -> getNestedRealmObjects(realmObject) }
       .also { realmObjects -> cascadeDelete(realmObjects) }

   notNullEntities
       .forEach { entity ->
         if((entity is RealmObject) && entity.isValid) {
           entity.deleteFromRealm()
         }
       }
 }
}

Өргөтгөл filterRealmObject зөвхөн Хүрээний объектуудыг шүүж дамжуулдаг. Арга getNestedRealmObjects эргэцүүлэн бодох замаар энэ нь бүх үүрлэсэн Realm объектуудыг олж, тэдгээрийг шугаман жагсаалтад оруулдаг. Дараа нь бид ижил зүйлийг рекурсив байдлаар хийдэг. Устгахдаа объектын хүчинтэй эсэхийг шалгах хэрэгтэй isValid, учир нь өөр өөр эх объектууд ижил объектуудтай байж болно. Үүнээс зайлсхийх нь дээр бөгөөд шинэ объект үүсгэхдээ id-г автоматаар үүсгэхийг ашиглах нь дээр.

Хүрээн дэх каскад устгалт удаан хугацааны турш хэрхэн ялсан тухай үлгэр

getNestedRealmObjects аргын бүрэн хэрэгжилт

private fun getNestedRealmObjects(realmObject: RealmObject) : List<RealmObject> {
 val nestedObjects = mutableListOf<RealmObject>()
 val fields = realmObject.javaClass.superclass.declaredFields

// Проверяем каждое поле, не является ли оно RealmModel или списком RealmList
 fields.forEach { field ->
   when {
     RealmModel::class.java.isAssignableFrom(field.type) -> {
       try {
         val child = getChildObjectByField(realmObject, field)
         child?.let {
           if (isInstanceOfRealmObject(it)) {
             nestedObjects.add(child as RealmObject)
           }
         }
       } catch (e: Exception) { ... }
     }

     RealmList::class.java.isAssignableFrom(field.type) -> {
       try {
         val childList = getChildObjectByField(realmObject, field)
         childList?.let { list ->
           (list as RealmList<*>).forEach {
             if (isInstanceOfRealmObject(it)) {
               nestedObjects.add(it as RealmObject)
             }
           }
         }
       } catch (e: Exception) { ... }
     }
   }
 }

 return nestedObjects
}

private fun getChildObjectByField(realmObject: RealmObject, field: Field): Any? {
 val methodName = "get${field.name.capitalize()}"
 val method = realmObject.javaClass.getMethod(methodName)
 return method.invoke(realmObject)
}

Үүний үр дүнд бид үйлчлүүлэгчийн коддоо өгөгдөл өөрчлөх үйлдэл бүрт "каскад устгах" аргыг ашигладаг. Жишээлбэл, оруулах үйлдлийн хувьд дараах байдалтай байна.

override fun <T : Entity> insert(
 entityInformation: EntityInformation,
 entities: Collection<T>): Collection<T> = entities.apply {
 realmInstance.cascadeDelete(getManagedEntities(entityInformation, this))
 realmInstance.copyFromRealm(
     realmInstance
         .copyToRealmOrUpdate(this.map { entity -> entity as RealmModel }
 ))
}

Эхний арга getManagedEntities бүх нэмэгдсэн объектуудыг хүлээн авч, дараа нь арга cascadeDelete Шинэ объект бичихээс өмнө цуглуулсан бүх объектыг рекурсив байдлаар устгана. Бид энэ аргыг програмын туршид ашигладаг. Realm дахь санах ойн алдагдлыг бүрэн арилгасан. Аппликешныг хүйтэн эхлүүлэх тооноос эхлүүлэх хугацаанаас хамаарах ижил хэмжилтийг хийсний дараа бид үр дүнг харж байна.

Хүрээн дэх каскад устгалт удаан хугацааны турш хэрхэн ялсан тухай үлгэр

Ногоон шугам нь үүрлэсэн объектуудыг автоматаар устгах үед програмыг эхлүүлэх хугацаа нь хүйтэн эхлэх тооноос хамаарч байгааг харуулж байна.

Үр дүн, дүгнэлт

Үргэлж өсөн нэмэгдэж буй Realm мэдээллийн сан нь програмыг маш удаан ажиллуулахад хүргэсэн. Бид үүрлэсэн объектуудын "үсэгчилсэн устгах" шинэчлэлтийг гаргасан. Одоо бид _app_start хэмжигдэхүүнээр дамжуулан бидний шийдвэр програмыг эхлүүлэх хугацаанд хэрхэн нөлөөлснийг хянаж, үнэлж байна.

Хүрээн дэх каскад устгалт удаан хугацааны турш хэрхэн ялсан тухай үлгэр

Шинжилгээ хийхийн тулд бид 90 хоногийн хугацааг авч үзэхэд: програмыг эхлүүлэх хугацаа нь дундаж болон хэрэглэгчдийн 95-р хувь нь буурч эхэлсэн бөгөөд цаашид өсөхөө больсон.

Хүрээн дэх каскад устгалт удаан хугацааны турш хэрхэн ялсан тухай үлгэр

Хэрэв та долоон өдрийн графикийг харвал _app_start хэмжигдэхүүн бүрэн хангалттай бөгөөд 1 секундээс бага хугацаатай байна.

_app_start-ын дундаж утга 5 секундээс хэтэрсэн тохиолдолд Firebase нь анхдагч байдлаар мэдэгдэл илгээдэг гэдгийг нэмж хэлэх нь зүйтэй. Гэсэн хэдий ч, бидний харж байгаагаар та үүнд найдах хэрэггүй, харин орж, тодорхой шалгах хэрэгтэй.

Realm мэдээллийн сангийн онцлог нь харилцаа холбоогүй мэдээллийн сан юм. Хэрэглэхэд хялбар, ORM шийдэлтэй төстэй, объектын холболттой хэдий ч энэ нь каскад устгалтгүй.

Хэрэв үүнийг анхаарч үзэхгүй бол үүрлэсэн объектууд хуримтлагдаж, "алдагдах" болно. Өгөгдлийн сан байнга өсөх бөгөөд энэ нь эргээд програмыг удаашруулах эсвэл эхлүүлэхэд нөлөөлнө.

Би хайрцагнаас гараагүй байгаа хэдий ч удаан хугацаанд яригдаж байгаа Realm дахь объектуудыг хэрхэн хурдан устгах талаар туршлагаа хуваалцсан. хэлэх и хэлэх. Манай тохиолдолд энэ нь програмыг эхлүүлэх хугацааг ихээхэн хурдасгасан.

Энэ шинж чанар удахгүй гарч ирэх талаар ярилцаж байгаа хэдий ч Realm-д каскадын устгал байхгүй нь дизайнаар хийгдсэн байдаг. Хэрэв та шинэ програм зохиож байгаа бол үүнийг анхаарч үзээрэй. Хэрэв та аль хэдийн Realm ашиглаж байгаа бол танд ийм асуудал байгаа эсэхийг шалгаарай.

Эх сурвалж: www.habr.com

сэтгэгдэл нэмэх