Xamarin Forms Azure移动应用程序同步缓慢

6
我正在使用Azure Mobile App与Xamarin.Forms创建一个离线移动应用程序。
我的解决方案基于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毫秒,因此问题似乎不是来自这里。
有人遇到同样的麻烦吗?我是否做错了什么或有改进同步性能的提示?

2
你解决这个问题了吗?我也遇到了。 - Tom Kulaga
同时在这方面遇到了很多问题。我们有相当大的数据集(最高达160行)。试图从一组50中提取需要大约2分30秒的时间。更进一步,即使数据已经存在于用户手机上,加载仍需花费约30-40秒的时间,即使没有进行任何更改。如果设备处于离线状态,则从手机上的SQLiteDB访问相同的数据几乎是瞬间完成的。 - Bejasc
1
经历了同样的事情。对我而言,它看起来像是一个内存问题。在表同步之间同步暂停以允许GC.Collect()。使用Xamarin Profiler,在同步结果中占用400-600兆字节 - 真痛苦:( - InquisitorJax
@InquisitorJax,你能从你的发现中做出任何改进吗? - Bejasc
很遗憾,我认为微软目前并没有给予Azure App Service太多关注。 - InquisitorJax
2个回答

0

慢速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;

0
我们遇到的问题与数据库迁移有关。数据库中的每一行都具有相同的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中提到的相同,还包括我在此处列出的改进。

我鼓励大家分享他们的解决方案或想法,以改善这种速度。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接