xamarin 形成 azure 移动应用程序慢速同步
Posted
技术标签:
【中文标题】xamarin 形成 azure 移动应用程序慢速同步【英文标题】:xamarin forms azure mobile apps slow sync 【发布时间】:2018-06-23 21:35:55 【问题描述】:我正在使用带有 Xamarin.Forms 的 Azure 移动应用程序来创建支持脱机的移动应用程序。
我的解决方案是基于https://adrianhall.github.io/develop-mobile-apps-with-csharp-and-azure/chapter3/client/
这是我用于离线同步的代码:
public class AzureDataSource
private async Task InitializeAsync()
// Short circuit - local database is already initialized
if (client.SyncContext.IsInitialized)
return;
// Define the database schema
store.DefineTable<ArrayElement>();
store.DefineTable<InputAnswer>();
//Same thing with 16 others table
...
// Actually create the store and update the schema
await client.SyncContext.InitializeAsync(store, new MobileServiceSyncHandler());
public async Task SyncOfflineCacheAsync()
await InitializeAsync();
//Check if authenticated
if (client.CurrentUser != null)
// Push the Operations Queue to the mobile backend
await client.SyncContext.PushAsync();
// Pull each sync table
var arrayTable = await GetTableAsync<ArrayElement>();
await arrayTable.PullAsync();
var inputAnswerInstanceTable = await GetTableAsync<InputAnswer>();
await inputAnswerInstanceTable.PullAsync();
//Same thing with 16 others table
...
public async Task<IGenericTable<T>> GetTableAsync<T>() where T : TableData
await InitializeAsync();
return new AzureCloudTable<T>(client);
public class AzureCloudTable<T>
public AzureCloudTable(MobileServiceClient client)
this.client = client;
this.table = client.GetSyncTable<T>();
public async Task PullAsync()
//Query name used for incremental pull
string queryName = $"incsync_typeof(T).Name";
await table.PullAsync(queryName, table.CreateQuery());
问题在于,即使没有任何东西可以拉取,同步也需要很长时间(android 设备上需要 8-9 秒,拉取整个数据库需要 25 秒以上)。
我查看了Fiddler 以了解移动应用后端响应需要多长时间,每个请求大约需要 50 毫秒,所以问题似乎不是来自这里。
有人遇到同样的问题吗?是否有什么我做错了什么或提示可以提高我的同步性能?
【问题讨论】:
你解决了吗?我也看到了 这方面也有很多麻烦。我们有相当大的数据集(最高为 160 行)。尝试做一个 50 组的拉动大约需要 2 分半钟。更进一步的问题是,即使用户手机上已经存在数据,即使没有进行任何更改,加载仍需要大约 30-40 秒。如果设备离线,从手机上的 SQLiteDB 访问相同的数据,几乎是即时的。 经历同样的事情。对我来说,这看起来像是一个内存问题。表同步之间的同步暂停以允许 GC.Collect()。使用 Xamarin Profiler,同步结果在 400 - 600 Megs 之间 - 哎哟:( @InquisitorJax 你能从你的发现中做出任何改进吗? @Bejasc 很遗憾没有 - 我认为 MS 并没有对 Azure App Service atm 给予太多关注 :( 【参考方案1】:Pull() 缓慢的原因之一是当超过 (10) 行获得相同的 UpdatedAt 值时。当您一次更新行时会发生这种情况,例如运行 SQL 命令。
解决此问题的一种方法是修改表上的默认触发器。为了确保每一行都有一个唯一的 UpdateAt,我们做了这样的事情:
ALTER TRIGGER [dbo].[TR_dbo_Items_InsertUpdateDelete] ON [dbo].[TableName]
AFTER INSERT, UPDATE, DELETE
AS
BEGIN
DECLARE @InsertedAndDeleted TABLE
(
Id NVARCHAR(128)
);
DECLARE @Count INT,
@Id NVARCHAR(128);
INSERT INTO @InsertedAndDeleted
SELECT Id
FROM inserted;
INSERT INTO @InsertedAndDeleted
SELECT Id
FROM deleted
WHERE Id NOT IN
(
SELECT Id
FROM @InsertedAndDeleted
);
--select * from @InsertedAndDeleted;
SELECT @Count = Count(*)
FROM @InsertedAndDeleted;
-- ************************ UpdatedAt ************************
-- while loop
WHILE @Count > 0
BEGIN
-- selecting
SELECT TOP (1) @Id = Id
FROM @InsertedAndDeleted;
-- updating
UPDATE [dbo].[TableName]
SET UpdatedAt = Convert(DATETIMEOFFSET, DateAdd(MILLISECOND, @Count, SysUtcDateTime()))
WHERE Id = @Id;
-- deleting
DELETE FROM @InsertedAndDeleted
WHERE id = @Id;
-- counter
SET @Count = @Count - 1;
END;
END;
【讨论】:
【参考方案2】:我们的特定问题与我们的数据库迁移有关。数据库中的每一行都有相同的updatedAt
值。我们运行了一个 SQL 脚本来修改它们,使它们都是唯一的。
此修复实际上是针对我们遇到的其他一些问题,即由于某种未知原因并非所有行都被返回,但我们也看到了显着的速度提升。
此外,另一个改进加载时间的奇怪修复如下。
在我们第一次提取所有数据之后(可以理解,这需要一些时间) - 我们对返回的一个行执行了UpdateAsync()
,并且我们执行了不要事后推它。
我们已经了解到离线同步的工作方式是,它将提取日期更新的任何内容,而不是最近更新的日期。与此相关的速度略有提高。
最后,我们为提高速度所做的最后一件事是不要再次获取数据,如果它已经在视图中缓存了一个副本。不过,这可能不适用于您的用例。
public List<Foo> fooList = new List<Foo>
public void DisplayAllFoo()
if(fooList.Count == 0)
fooList = await SyncClass.GetAllFoo();
foreach(var foo in fooList)
Console.WriteLine(foo.bar);
2019 年 3 月 20 日编辑: 有了这些改进,我们仍然看到非常慢的同步操作,其使用方式与 OP 中提到的相同,还包括我在此处的答案中列出的改进。
我鼓励所有人分享他们关于如何提高速度的解决方案或想法。
【讨论】:
以上是关于xamarin 形成 azure 移动应用程序慢速同步的主要内容,如果未能解决你的问题,请参考以下文章
Xamarin MonoAndroid Azure 移动服务 InsertAsync
Azure 移动服务 Xamarin.Android 推送通知示例应用程序出现问题
在 Xamarin 移动应用程序中显示存储在 Azure 存储中的 Blob/照片
使用 PCL 和 Xamarin 对 Azure 移动服务执行单元测试时程序集版本不匹配