Cosmos CreateDocumentQuery linq Производительность в зависимости от состояния - PullRequest
0 голосов
/ 18 декабря 2018

У меня есть коллекция космоса, имеющая где-то около 28000 документов, и я использую CreateDocumentQuery для DocumentClient с условием where для свойств типа 'T'.С различными типами использования, упомянутыми ниже, я получаю очень резкую разницу во времени задержки при получении результатов.

Случай 1:

    var docs2 = 
    _documentClient.CreateDocumentQuery<HeartRateDayRecordIdentifierData>(collectionUri).Where(x =>
           x.SubjectDeviceInformation.StudyId == "TestStudy"
           && x.SubjectDeviceInformation.SiteId == "Site_._Street_23"
           && x.SubjectDeviceInformation.SubjectId == "Subject3"
           && x.SubjectDeviceInformation.DeviceId == "Device1"
           && x.DaySplit == "20181112").AsEnumerable().FirstOrDefault(); 

Случай 2: Это тот же код и условие, но на этот раз я использую переменную функции для декальрации условия where.

Func<HeartRateDayRecordIdentifierData, bool> searchOptions = x =>
        x.SubjectDeviceInformation.StudyId == "TestStudy"
        && x.SubjectDeviceInformation.SiteId == "Site_._Street_23"
        && x.SubjectDeviceInformation.SubjectId == "Subject3"
        && x.SubjectDeviceInformation.DeviceId == "Device1"
        && x.DaySplit == "20181112";

var docs1 = _documentClient.CreateDocumentQuery<HeartRateDayRecordIdentifierData>(collectionUri)
                        .Where(searchOptions).AsEnumerable().FirstOrDefault();

Case 1 , который имеет встроенный параметр возврата условиярезультаты в промежутке времени меньше секунды, где, как в Случай 2 , результат занимает около 20-30 секунд, что кажется немного странным.Я не понимаю, в чем разница между наличием встроенного условия где и передачей условия в качестве допустимого.

Если кто-то заинтересовался образцом космического документа:

{
    "id": "TestStudy_Site_._Street_21_Subject1_Device1_20181217",
    "AssemblyVersion": "1.2.3.0",
    "DataItemId": "20181217/TestStudy_Site_._Street_21_Subject1_Device1_20181217",
    "MessageType": "HeartRateDayDocumentIdentifier",
    "TimeStamp": "2018-12-14T00:00:00",
    "DaySplit": "20181217",
    "SubjectDeviceInformation": {
        "SubjectId": "Subject1",
        "DeviceId": "Device1",
        "StudyId": "TestStudy",
        "SiteId": "Site_._Street_21"
    }   
}

и Вот модель, используемаядля десериализации документа: внутренний класс HeartRateDayRecordIdentifierData {public string id {get;задавать;}

    public string AssemblyVersion { get; set; }

    public string DataItemId { get; set; }

    public string MessageType { get; set; }

    public DateTime TimeStamp { get; set; }

    public string DaySplit { get; set; }

    public SubjectDeviceInformation SubjectDeviceInformation { get; set; }
}

internal class SubjectDeviceInformation
{
    public string SubjectId { get; set; }

    public string DeviceId { get; set; }

    public string StudyId { get; set; }

    public string SiteId { get; set; }
}

Любые предложения о том, что я не так делаю, я делаю здесь.

1 Ответ

0 голосов
/ 18 декабря 2018

В обоих случаях вы делаете это неоптимальным способом.

Вы хотите сначала или ноль, если нет совпадения.

Однако вы делаете синхронный вызов запроса между разделамипозвонив по номеру AsEnumerable().FirstOrDefault().

Кроме того, ваше условие where должно быть Expression<Func<HeartRateDayRecordIdentifierData, bool>> вместо Func.

. В обоих случаях вначале вы возвращаете все данные в CosmosDB.И ТОГДА LINQ выполняет фильтрацию в памяти, чтобы вернуть вам данные.

Вместо этого вам следует использовать методы while(query.HasMoreResults) и query.ExecuteNextAsync() для возврата данных.

Вот как должен выглядеть ваш запрос:

public async Task<HeartRateDayRecordIdentifierData> GetSomethingAsync()
{
    var query = 
        _documentClient.CreateDocumentQuery<HeartRateDayRecordIdentifierData>(collectionUri).Where(x =>
               x.SubjectDeviceInformation.StudyId == "TestStudy"
               && x.SubjectDeviceInformation.SiteId == "Site_._Street_23"
               && x.SubjectDeviceInformation.SubjectId == "Subject3"
               && x.SubjectDeviceInformation.DeviceId == "Device1"
               && x.DaySplit == "20181112").AsDocumentQuery();

    while(query.HasMoreResults)
    {
        var results = await query.ExecuteNextAsync();
        if(results.Any())
            return results.First();     
    }          

    return null;
}

Таким образом, SDK выполняет минимальное количество вызовов для сопоставления данных и не запрашивает все возможные документы.

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

Вы также можете абстрагировать все это и просто использовать ваши объекты и метод .FirstOrDefaultAsync, если выиспользовать Космонавт .Таким образом, весь ваш код может измениться на следующее:

public async Task<HeartRateDayRecordIdentifierData> GetSomethingAsync()
{
    return await cosmosStore.Query().Where(x =>
                   x.SubjectDeviceInformation.StudyId == "TestStudy"
                   && x.SubjectDeviceInformation.SiteId == "Site_._Street_23"
                   && x.SubjectDeviceInformation.SubjectId == "Subject3"
                   && x.SubjectDeviceInformation.DeviceId == "Device1"
                   && x.DaySplit == "20181112").FirstOrDefaultAsync();
}

Вы можете сами выбирать, какой путь вам подходит. Отказ от ответственности, я создатель Космонавта.

...