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.
This commit is contained in:
Xiangzhi Sheng 2016-11-29 10:24:56 +08:00
Родитель 768d78db9e
Коммит 0f663eedda
3 изменённых файлов: 14 добавлений и 14 удалений

Просмотреть файл

@ -72,6 +72,7 @@
<HintPath>..\..\packages\Microsoft.Azure.Devices.Client.1.0.16\lib\net45\Microsoft.Azure.Devices.Client.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.Azure.Documents.Client, Version=1.9.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<Reference Include="Microsoft.Data.Edm, Version=5.6.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Data.Edm.5.6.4\lib\net40\Microsoft.Data.Edm.dll</HintPath>
<Private>True</Private>

Просмотреть файл

@ -12,7 +12,7 @@ namespace Microsoft.Azure.Devices.Applications.RemoteMonitoring.DeviceAdmin.Infr
{
public class DeviceRegistryRepository : IDeviceRegistryCrudRepository, IDeviceRegistryListRepository
{
private readonly IDocumentDBClient<DeviceModel> _documentClient;
protected readonly IDocumentDBClient<DeviceModel> _documentClient;
public DeviceRegistryRepository(IDocumentDBClient<DeviceModel> documentClient)
{

Просмотреть файл

@ -71,27 +71,26 @@ namespace Microsoft.Azure.Devices.Applications.RemoteMonitoring.DeviceAdmin.Infr
public override async Task<DeviceListQueryResult> 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<DeviceModel> SortDeviceList(IQueryable<DeviceModel> deviceList, string sortColumn, QuerySortOrder sortOrder)
private IQueryable<Twin> SortDeviceList(IQueryable<Twin> 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<DeviceModel, dynamic> keySelector = item => item.Twin.Get(sortColumn);
Func<Twin, dynamic> keySelector = twin => twin.Get(sortColumn);
if (sortOrder == QuerySortOrder.Ascending)
{