javascript - query - angularfirestore
Problema de rendimiento lento de Firestore al obtener datos (4)
Tengo problemas de rendimiento lento con Firestore al recuperar datos básicos almacenados en un documento en comparación con la base de datos en tiempo real con una proporción de 1/10.
Usando Firestore, toma un promedio de 3000 ms en la primera llamada
this.db.collection(‘testCol’)
.doc(‘testDoc’)
.valueChanges().forEach((data) => {
console.log(data);//3000 ms later
});
Usando la base de datos en tiempo real, toma un promedio de 300 ms en la primera llamada
this.db.database.ref(‘/test’).once(‘value’).then(data => {
console.log(data); //300ms later
});
Esta es una captura de pantalla de la consola de red:
Estoy ejecutando Javascript SDK v4.50 con AngularFire2 v5.0 rc.2.
¿Alguien experimentó este problema?
Tuve este problema hasta esta mañana. Mi consulta de Firestore a través de iOS / Swift tomaría alrededor de 20 segundos para completar una consulta simple, completamente indexada, con tiempos de consulta no proporcionales para 1 artículo devuelto, hasta 3.000.
Mi solución fue desactivar la persistencia de datos fuera de línea. En mi caso, no se ajustaba a las necesidades de nuestra base de datos de Firestore, que tiene grandes porciones de sus datos actualizados todos los días.
Los usuarios de iOS y Android tienen esta opción habilitada de manera predeterminada, mientras que los usuarios web la tienen deshabilitada de manera predeterminada. Hace que Firestore parezca increíblemente lento si está consultando una gran colección de documentos. Básicamente, almacena en caché una copia de los datos que está consultando (y cualquier colección que esté consultando, creo que almacena en caché todos los documentos), lo que puede conducir a un uso elevado de la memoria.
En mi caso, causó una gran espera para cada consulta hasta que el dispositivo haya almacenado en caché los datos requeridos, de ahí los tiempos de consulta no proporcionales para que el número creciente de artículos regrese de la misma colección. Esto se debe a que tomó la misma cantidad de tiempo almacenar en caché la colección en cada consulta.
Datos sin conexión: de los documentos de Cloud Firestore
Realicé algunas evaluaciones comparativas para mostrar este efecto (con la persistencia fuera de línea habilitada) de la misma colección consultada, pero con diferentes cantidades de elementos devueltos utilizando el parámetro .limit:
Ahora con 100 elementos devueltos (con la persistencia fuera de línea deshabilitada), mi consulta tarda menos de 1 segundo en completarse.
Mi código de consulta de Firestore está a continuación:
let db = Firestore.firestore()
self.date = Date()
let ref = db.collection("collection").whereField("Int", isEqualTo: SomeInt).order(by: "AnotherInt", descending: true).limit(to: 100)
ref.getDocuments() { (querySnapshot, err) in
if let err = err {
print("Error getting documents: /(err)")
} else {
for document in querySnapshot!.documents {
let data = document.data()
//Do things
}
print("QUERY DONE")
let currentTime = Date()
let components = Calendar.current.dateComponents([.second], from: self.date, to: currentTime)
let seconds = components.second!
print("Elapsed time for Firestore query -> /(seconds)s")
// Benchmark result
}
}
bueno, por lo que estoy haciendo e investigando actualmente usando nexus 5X en el emulador y el teléfono Android real Huawei P8,
Firestore y Cloud Storage me dan un dolor de cabeza de respuesta lenta cuando hago el primer document.get () y el primer storage.getDownloadUrl ()
Me da más de 60 segundos de respuesta en cada solicitud. La respuesta lenta solo ocurre en teléfonos Android reales. No en el emulador. Otra cosa extraña. Después del primer encuentro, la solicitud de descanso es fluida.
Aquí está el código simple donde encuentro la respuesta lenta.
var dbuserref = dbFireStore.collection(''user'').where(''email'',''=='',email);
const querySnapshot = await dbuserref.get();
var url = await defaultStorage.ref(document.data().image_path).getDownloadURL();
También encontré un enlace que está investigando lo mismo. https://reformatcode.com/code/android/firestore-document-get-performance
ACTUALIZACIÓN: 12 de febrero de 2018 - iOS Firestore SDK v0.10.0
Al igual que algunos otros comentaristas, también noté una respuesta más lenta en la primera solicitud de obtención (con solicitudes posteriores que demoran ~ 100 ms). Para mí no es tan malo como 30s, pero tal vez alrededor de 2-3s cuando tengo buena conectividad, lo cual es suficiente para proporcionar una mala experiencia de usuario cuando se inicia mi aplicación.
Firebase ha informado que están al tanto de este problema de "arranque en frío" y están trabajando en una solución a largo plazo para ello, desafortunadamente no hay ETA. Creo que es un problema separado que cuando tengo una conectividad deficiente, pueden pasar años (más de 30 segundos) antes de que las solicitudes decidan leer desde la memoria caché.
Mientras Firebase soluciona todos estos problemas, comencé a usar los nuevos
disableNetwork()
y
enableNetwork()
(disponibles en Firestore v0.10.0) para controlar manualmente el estado en línea / fuera de línea de Firebase.
Aunque he tenido que tener
mucho
cuidado donde lo uso en mi código, ya que hay un error de Firestore que puede causar un bloqueo en ciertos escenarios.
ACTUALIZACIÓN: 15 de noviembre de 2017 - iOS Firestore SDK v0.9.2
Parece que el problema de rendimiento lento ahora se ha solucionado. He vuelto a ejecutar las pruebas que se describen a continuación y el tiempo que le toma a Firestore devolver los 100 documentos ahora parece estar alrededor de los 100 ms.
No estoy seguro de si esto fue una solución en el último SDK v0.9.2 o si fue una solución de back-end (o ambos), pero sugiero que todos actualicen sus pods de Firebase. Mi aplicación es notablemente más receptiva, de forma similar a como estaba en el Realtime DB.
También descubrí que Firestore es mucho más lento que Realtime DB, especialmente al leer muchos documentos.
Pruebas actualizadas (con el último SDK de iOS Firestore v0.9.0):
Configuré un proyecto de prueba en iOS Swift usando RTDB y Firestore y ejecuté 100 operaciones de lectura secuencial en cada una. Para el RTDB, probé el observeSingleEvent y los métodos de observación en cada uno de los 100 nodos de nivel superior. Para Firestore, utilicé los métodos getDocument y addSnapshotListener en cada uno de los 100 documentos de la colección TestCol. Ejecuté las pruebas con la persistencia del disco por intervalos. Consulte la imagen adjunta, que muestra la estructura de datos para cada base de datos.
Ejecuté la prueba 10 veces para cada base de datos en el mismo dispositivo y una red wifi estable. Los observadores y oyentes existentes fueron destruidos antes de cada nueva carrera.
Método de DB en tiempo real observeSingleEvent:
func rtdbObserveSingle() {
let start = UInt64(floor(Date().timeIntervalSince1970 * 1000))
print("Started reading from RTDB at: /(start)")
for i in 1...100 {
Database.database().reference().child(String(i)).observeSingleEvent(of: .value) { snapshot in
let time = UInt64(floor(Date().timeIntervalSince1970 * 1000))
let data = snapshot.value as? [String: String] ?? [:]
print("Data: /(data). Returned at: /(time)")
}
}
}
Método de observación DB en tiempo real:
func rtdbObserve() {
let start = UInt64(floor(Date().timeIntervalSince1970 * 1000))
print("Started reading from RTDB at: /(start)")
for i in 1...100 {
Database.database().reference().child(String(i)).observe(.value) { snapshot in
let time = UInt64(floor(Date().timeIntervalSince1970 * 1000))
let data = snapshot.value as? [String: String] ?? [:]
print("Data: /(data). Returned at: /(time)")
}
}
}
Método getDocument de Firestore:
func fsGetDocument() {
let start = UInt64(floor(Date().timeIntervalSince1970 * 1000))
print("Started reading from FS at: /(start)")
for i in 1...100 {
Firestore.firestore().collection("TestCol").document(String(i)).getDocument() { document, error in
let time = UInt64(floor(Date().timeIntervalSince1970 * 1000))
guard let document = document, document.exists && error == nil else {
print("Error: /(error?.localizedDescription ?? "nil"). Returned at: /(time)")
return
}
let data = document.data() as? [String: String] ?? [:]
print("Data: /(data). Returned at: /(time)")
}
}
}
Método addSnapshotListener de Firestore:
func fsAddSnapshotListener() {
let start = UInt64(floor(Date().timeIntervalSince1970 * 1000))
print("Started reading from FS at: /(start)")
for i in 1...100 {
Firestore.firestore().collection("TestCol").document(String(i)).addSnapshotListener() { document, error in
let time = UInt64(floor(Date().timeIntervalSince1970 * 1000))
guard let document = document, document.exists && error == nil else {
print("Error: /(error?.localizedDescription ?? "nil"). Returned at: /(time)")
return
}
let data = document.data() as? [String: String] ?? [:]
print("Data: /(data). Returned at: /(time)")
}
}
}
Cada método esencialmente imprime la marca de tiempo de Unix en milisegundos cuando el método comienza a ejecutarse y luego imprime otra marca de tiempo de Unix cuando vuelve cada operación de lectura. Tomé la diferencia entre la marca de tiempo inicial y la última marca de tiempo para volver.
RESULTADOS - Persistencia del disco deshabilitada:
RESULTADOS - Persistencia de disco habilitada:
Estructura de datos:
Cuando los métodos getDocument / addSnapshotListener de Firestore se atascan, parece atascarse durante duraciones que son aproximadamente múltiplos de 30 segundos. ¿Quizás esto podría ayudar al equipo de Firebase a aislar en qué parte del SDK se está atascando?
Fecha de actualización 02 de marzo de 2018
Parece que este es un problema conocido y los ingenieros de Firestore están trabajando en una solución. Después de algunos intercambios de correo electrónico y código compartido con un ingeniero de Firestore sobre este tema, esta fue su respuesta a partir de hoy.
"En realidad está en lo correcto. Tras una comprobación adicional, esta lentitud en la API getDocuments () es un comportamiento conocido en Cloud Firestore beta. Nuestros ingenieros son conscientes de este problema de rendimiento etiquetado como" arranque en frío ", pero no se preocupen como lo estamos haciendo. nuestro mejor esfuerzo para mejorar el rendimiento de consultas de Firestore.
Ya estamos trabajando en una solución a largo plazo, pero no puedo compartir ningún cronograma o detalles en este momento. Si bien Firestore aún está en versión beta, se espera que haya más mejoras por venir ".
Esperemos que esto sea eliminado pronto.
Usando Swift / iOS
Después de lidiar con esto durante aproximadamente 3 días, parece que el problema es definitivamente el get (), es decir .getDocuments y .getDocument. Cosas que pensé que estaban causando retrasos extremos pero intermitentes, pero no parece ser el caso:
- No tan buena conectividad de red
- Llamadas repetidas por bucle sobre .getDocument ()
- Encadenamiento de llamadas get ()
- Firestore Arranque en frío
- Recuperar varios documentos (Recuperar 1 documento pequeño causó retrasos de 20 segundos)
- Almacenamiento en caché (deshabilité la persistencia sin conexión pero esto no hizo nada).
Pude descartar todo esto porque noté que este problema no ocurría con cada llamada a la base de datos de Firestore que estaba haciendo. Solo recuperaciones usando get (). Para patadas, reemplacé .getDocument con .addSnapshotListener para recuperar mis datos y listo. Recuperación instantánea cada vez, incluida la primera llamada. No comienza el frío. Hasta ahora no hay problemas con el .addSnapshotListener, solo getDocument (s).
Por ahora, simplemente estoy soltando .getDocument () donde el tiempo es esencial y reemplazándolo con .addSnapshotListener y luego usando
for document in querySnapshot!.documents{
// do some magical unicorn stuff here with my document.data()
}
... para seguir avanzando hasta que Firestore resuelva esto.