From 0f663eeddac6dab905dc6cc41480756d2556e3d5 Mon Sep 17 00:00:00 2001 From: Xiangzhi Sheng Date: Tue, 29 Nov 2016 10:24:56 +0800 Subject: [PATCH] Improve performance for device query Currently, device metadata was stored in two place - DocumentDB (for command, telemetries, etc.) and IoT Hub (for twin). We must try to merge those two data source for each query. In previous code, we query Document DB separately for each devices we retrieved from the IoT Hub. It may cause redundant initializing effort. In this code change, we use one single query for all the devices to improve the performance. Furthermore, we are going to delay the query on Document DB until the result was paginated. It will bring some benefit for pagination case. --- .../Infrastructure/Infrastructure.csproj | 1 + .../Repository/DeviceRegistryRepository.cs | 2 +- .../DeviceRegistryRepositoryWithIoTHubDM.cs | 25 +++++++++---------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/DeviceAdministration/Infrastructure/Infrastructure.csproj b/DeviceAdministration/Infrastructure/Infrastructure.csproj index 573e6b7d..b59bfa6b 100644 --- a/DeviceAdministration/Infrastructure/Infrastructure.csproj +++ b/DeviceAdministration/Infrastructure/Infrastructure.csproj @@ -72,6 +72,7 @@ ..\..\packages\Microsoft.Azure.Devices.Client.1.0.16\lib\net45\Microsoft.Azure.Devices.Client.dll True + ..\..\packages\Microsoft.Data.Edm.5.6.4\lib\net40\Microsoft.Data.Edm.dll True diff --git a/DeviceAdministration/Infrastructure/Repository/DeviceRegistryRepository.cs b/DeviceAdministration/Infrastructure/Repository/DeviceRegistryRepository.cs index 936ffd4d..7b533049 100644 --- a/DeviceAdministration/Infrastructure/Repository/DeviceRegistryRepository.cs +++ b/DeviceAdministration/Infrastructure/Repository/DeviceRegistryRepository.cs @@ -12,7 +12,7 @@ namespace Microsoft.Azure.Devices.Applications.RemoteMonitoring.DeviceAdmin.Infr { public class DeviceRegistryRepository : IDeviceRegistryCrudRepository, IDeviceRegistryListRepository { - private readonly IDocumentDBClient _documentClient; + protected readonly IDocumentDBClient _documentClient; public DeviceRegistryRepository(IDocumentDBClient documentClient) { diff --git a/DeviceAdministration/Infrastructure/Repository/DeviceRegistryRepositoryWithIoTHubDM.cs b/DeviceAdministration/Infrastructure/Repository/DeviceRegistryRepositoryWithIoTHubDM.cs index 2f047be7..219f96bd 100644 --- a/DeviceAdministration/Infrastructure/Repository/DeviceRegistryRepositoryWithIoTHubDM.cs +++ b/DeviceAdministration/Infrastructure/Repository/DeviceRegistryRepositoryWithIoTHubDM.cs @@ -71,27 +71,26 @@ namespace Microsoft.Azure.Devices.Applications.RemoteMonitoring.DeviceAdmin.Infr public override async Task GetDeviceList(DeviceListQuery query) { + // Kick-off DocDB query initializing + var queryTask = this._documentClient.QueryAsync(); + // Considering all the device properties was copied to IoT Hub twin as tag or // reported property, we will only query on the IoT Hub twins. The DocumentDB // will not be touched. - var twins = await this._deviceManager.QueryDevicesAsync(query); - - var tasks = twins.Select(async twin => - { - var device = await base.GetDeviceAsync(twin.DeviceId); - device.Twin = twin; - return device; - }); - - var filteredDevices = await Task.WhenAll(tasks); + var filteredDevices = await this._deviceManager.QueryDevicesAsync(query); var sortedDevices = this.SortDeviceList(filteredDevices.AsQueryable(), query.SortColumn, query.SortOrder); var pagedDeviceList = sortedDevices.Skip(query.Skip).Take(query.Take).ToList(); + // Query on DocDB for traditional device properties, commands and so on + var deviceIds = pagedDeviceList.Select(twin => twin.DeviceId); + var deviceModels = (await queryTask).Where(x => deviceIds.Contains(x.DeviceProperties.DeviceID)).ToList(); + deviceModels.ForEach(d => d.Twin = filteredDevices.Single(t => t.DeviceId == d.DeviceProperties.DeviceID)); + return new DeviceListQueryResult { - Results = pagedDeviceList, + Results = deviceModels, TotalDeviceCount = (int)await this._deviceManager.GetDeviceCountAsync(), TotalFilteredCount = filteredDevices.Count() }; @@ -107,7 +106,7 @@ namespace Microsoft.Azure.Devices.Applications.RemoteMonitoring.DeviceAdmin.Infr await this._deviceManager.UpdateTwinAsync(deviceId, twin); } - private IQueryable SortDeviceList(IQueryable deviceList, string sortColumn, QuerySortOrder sortOrder) + private IQueryable SortDeviceList(IQueryable deviceList, string sortColumn, QuerySortOrder sortOrder) { // if a sort column was not provided then return the full device list in its original sort if (string.IsNullOrWhiteSpace(sortColumn)) @@ -115,7 +114,7 @@ namespace Microsoft.Azure.Devices.Applications.RemoteMonitoring.DeviceAdmin.Infr return deviceList; } - Func keySelector = item => item.Twin.Get(sortColumn); + Func keySelector = twin => twin.Get(sortColumn); if (sortOrder == QuerySortOrder.Ascending) {