Подтвердить что ты не робот

Низкая производительность Firestore при получении данных

У меня возникают проблемы с производительностью с Firestore при извлечении базовых данных, хранящихся в документе, по сравнению с базой данных в реальном времени с коэффициентом 1/10.

Используя Firestore, он занимает в среднем 3000 мс при первом вызове

 this.db.collection(‘testCol’)
   .doc(‘testDoc’)
   .valueChanges().forEach((data) => {
     console.log(data);//3000 ms later
 });

Используя базу данных реального времени, при первом вызове он занимает в среднем 300 мс

 this.db.database.ref(‘/test’).once(‘value’).then(data => {
     console.log(data); //300ms later
 });

Это скриншот сетевой консоли:

Firestore slow performance issue get Data

Я запускаю Javascript SDK v4.50 с AngularFire2 v5.0 rc.2.

Кто-нибудь испытал эту проблему?

4b9b3361

Ответ 1

ОБНОВЛЕНИЕ: 15 ноября 2017 г. - iOS Firestore SDK v0.9.2

Кажется, что проблема с медленной производительностью теперь исправлена. Я повторно запускаю тесты, описанные ниже, и время, которое требуется для того, чтобы Firestore вернул 100 документов, похоже, постоянно составляет около 100 мс.

Не уверен, что это было исправление в последнем SDK v0.9.2, или если это исправление для бэкэнд (или и то, и другое), но я предлагаю всем обновить свои модули Firebase. Мое приложение заметно более отзывчивое - похоже на то, как оно было в базе данных реального времени.


Я также обнаружил, что Firestore намного медленнее, чем БД Realtime, особенно при чтении из большого количества документов.

Обновленные тесты (с последним iOS Firestore SDK v0.9.0):

Я установил тестовый проект в iOS Swift с использованием как RTDB, так и Firestore и выполнил по 100 последовательных операций чтения для каждого. Для RTDB я протестировал функцию observSingleEvent и наблюдал методы на каждом из 100 узлов верхнего уровня. Для Firestore я использовал методы getDocument и addSnapshotListener в каждом из 100 документов в коллекции TestCol. Я запускал тесты с постоянным диском. Пожалуйста, обратитесь к прилагаемому изображению, которое показывает структуру данных для каждой базы данных.

Я провел тест 10 раз для каждой базы данных на одном устройстве и стабильной сети Wi-Fi. Существующие наблюдатели и слушатели были уничтожены перед каждым новым прогоном.

Метод наблюдения в режиме реального времени DBSignSingleEvent:

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

Метод наблюдения в режиме реального времени:

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

Метод Firestore getDocument:

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

Метод Firestore addSnapshotListener:

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

Каждый метод по существу печатает временную метку unix в миллисекундах, когда метод начинает выполнение, а затем печатает еще одну временную метку unix, когда возвращается каждая операция чтения. Я получил разницу между начальной меткой времени и последней меткой времени, чтобы вернуться.

РЕЗУЛЬТАТЫ - Непрерывность диска отключена:

Непрерывность диска отключена

РЕЗУЛЬТАТЫ - Устойчивость диска:

Постоянство диска включено

Структура данных:

Структура данных

Когда методы Firestore getDocument/addSnapshotListener застревают, кажется, что они застряли на длительности, которые примерно кратные 30 секундам. Возможно, это может помочь команде Firebase изолировать, где в SDK он застревает?

Ответ 2

У меня была эта проблема до сегодняшнего утра. Мой запрос Firestore через iOS/Swift займет около 20 секунд, чтобы выполнить простой, полностью проиндексированный запрос - с непропорциональным временем запроса для 1 возвращенного элемента - вплоть до 3000.

Мое решение состояло в том, чтобы отключить постоянное сохранение данных в автономном режиме. В моем случае это не устраивало потребности нашей базы данных Firestore, которая ежедневно обновляет большую часть своих данных.

У пользователей iOS и Android этот параметр включен по умолчанию, в то время как веб-пользователи отключили его по умолчанию. Это заставляет Firestore казаться безумно медленным, если вы запрашиваете огромную коллекцию документов. В основном он кэширует копию любых данных, которые вы запрашиваете (и какую бы информацию вы ни запрашивали, я считаю, что она кэширует все документы внутри), что может привести к высокому использованию памяти.

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

Offline Data - из Документов облачного Firestore

Я выполнил некоторый бенчмаркинг, чтобы отобразить этот эффект (с автономной поддержкой продолжительности) из той же самой запрошенной коллекции, но с разными количествами элементов, возвращаемых с использованием параметра .limit:

Benchmarks Теперь на 100 возвращенных элементах (при отключенном отключении офлайн) мой запрос занимает менее 1 секунды.

Ниже приведен код запроса Firestore:

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

Ответ 3

хорошо, из того, что я сейчас делаю, и исследования, используя Nexus 5X в эмуляторе и реальном Android-телефоне Huawei P8,

Firestore и Cloud Storage обе дают мне головную боль медленного ответа когда я делаю сначала document.get() и first storage.getDownloadUrl()

Это дает мне более 60 секунд ответа на каждый запрос. Медленный ответ происходит только в реальном телефоне Android. Не в эмуляторе. Еще одна странная вещь. После первой встречи запрос останова будет плавным.

Вот простой код, где я встречаю медленный ответ.

var dbuserref = dbFireStore.collection('user').where('email','==',email);
const querySnapshot = await dbuserref.get();

var url = await defaultStorage.ref(document.data().image_path).getDownloadURL();

Я также нашел ссылку, которая исследует то же самое. https://reformatcode.com/code/android/firestore-document-get-performance