在Android上同时将数据保存在内存和数据库中的最佳实践

时间:2010-09-09 18:55:22

标签: android performance memcached architecture design-guidelines

我们正在设计一个拥有大量数据的Android应用程序(“客户”,“产品”,“订单”......),我们不希望每次需要某些记录时都查询SQLite。我们希望避免尽可能多地查询数据库,因此我们决定将某些数据始终保留在内存中。

我们最初的想法是创建两个简单的类:

  1. “MemoryRecord”:一个基本上包含对象数组(string,int,double,datetime等)的类,它们是表记录中的数据,以及获取这些数据的所有方法数据输入/输出此数组。

  2. “MemoryTable”:一个基本上包含[Key,MemoryRecord] Map和所有操作此Map并在数据库中插入/更新/删除记录的方法的类。

  3. 这些类将派生到我们在数据库中的每种表。当然还有其他有用的方法没有在上面列出,但它们在这一点上并不重要。

    因此,在启动应用程序时,我们将使用这些类将这些表从SQLite数据库加载到内存中,每次我们需要更改某些数据时,我们都会更改内存并将其发布到数据库中。 / p>

    但是,我们需要您的一些帮助/建议。你能提出一些更简单或更有效的方法来实现这样的事情吗?或者也许已经为我们做过一些现有的课程了?

    我理解你们要向我们展示的内容,我感谢你们。

    但是,假设我们有一个包含2000条记录的表格,我需要列出这些记录。对于每一个,我必须查询其他30个表(其中一些有1000条记录,其他有10条记录)在列表中添加其他信息,而这是“飞行”(如你所知,我们必须非常快)此时此刻)。

    现在您将要说:“只需使用所有这些'连接'构建您的主查询,并一步完成您所需的一切。如果数据库设计合理,SQLite可以非常快,等等。 。“

    好的,但是这个查询会变得非常复杂和确定,即使SQLite非常快,它也会“太慢”(2个4秒,我确认,这对我们来说这不是一个可接受的时间)

    另一个复杂因素是,根据用户交互,我们需要“重新查询”所有记录,因为所涉及的表不一样,我们必须与另一组表“重新加入”。

    因此,另一种方法是只带主要记录(这不会改变,无论用户做什么或想做什么)没有连接(这非常快!)并且每次我们想要一些数据时查询其他表。请注意,在仅包含10条记录的表中,我们将多次获取相同的记录。在这种情况下,这是浪费时间,因为无论SQLite是快速的,查询,游标,获取等等总是会比从一种“内存缓存”中获取记录更昂贵。我想明确指出,我们不打算始终将所有数据保存在内存中,只是我们经常查询的一些表。

    我们提出了最初的问题:“缓存”这些记录的最佳方法是什么?我真的很想把讨论集中在那里而不是“为什么你需要缓存数据?”

2 个答案:

答案 0 :(得分:66)

平台上的绝大多数应用(联系人,电子邮件,Gmail,日历等)都不会这样做。其中一些具有极其复杂的数据库模式,可能包含大量数据,因此无需执行此操作。你提出的建议是为你造成巨大的痛苦,没有明显的好处。

您应该首先关注设计数据库和架构,以便能够进行有效的查询。我认为数据库访问速度缓慢有两个主要原因:

  • 您的数据模式非常复杂。
  • 您的数据非常多。

如果您要获得大量数据,那么无论如何都无法将其全部保留在内存中,因此这是一个死胡同。如果您有复杂的结构,那么在任何一种情况下都可以通过优化它们来提高性能。在这两种情况下,您的数据库架构将是良好性能的关键。

实际上优化模式可能有点像黑色艺术(我不是它的专家),但要注意的一些事情是正确地创建你要查询的行上的索引,设计连接以便它们将有效道路等。我相信有很多人可以帮助你解决这个问题。

您还可以尝试查看某些平台数据库的来源,以获得有关如何设计以获得良好性能的一些想法。例如,Contacts数据库(特别是从2.0开始)非常复杂,并且需要进行大量优化,以便在具有大量不同类型查询的相对较大的数据和可扩展数据集上提供良好的性能。

更新

这里很好地说明了数据库优化的重要性。在Android的媒体提供商数据库中,该平台的较新版本显着改变了架构以添加一些新功能。将现有媒体数据库修改为新架构的升级代码可能需要8分钟或更长时间才能执行。

工程师进行了一项优化,将实际测试数据库的升级时间从8分钟缩短为8秒。性能提升60倍。

这是什么优化?

在升级时,在升级操作中使用的重要列上创建临时索引。 (然后在完成后将其删除。)因此,即使它还包括在升级期间使用的其中一列上构建索引所需的时间,也会提高60倍的性能。

SQLite就是其中之一,如果你知道自己在做什么,它就会非常高效。如果你不注意如何使用它,你最终可能会有糟糕的表现。不过,如果您遇到性能问题,可以通过改进SQLite的使用方式来修复它们,这是一个安全的选择。

答案 1 :(得分:5)

内存缓存的问题当然是您需要使其与数据库保持同步。我发现查询数据库实际上非常快,你可能在这里进行预优化。我对使用不同数据集的查询进行了大量测试,它们的持续时间从不超过10-20毫秒。

当然,这完全取决于您使用数据的方式。 ListViews经过了很好的优化,可以处理大量的行(我已经测试了5000行,没有真正的问题)。

如果您要继续使用内存缓存,您可能希望数据库在内容更改时通知缓存,然后您可以更新缓存。这样,任何人都可以在不知道缓存的情况下更新数据库。此外,如果您在数据库上构建ContentProvider,则可以使用ContentResolver在使用registerContentObserver注册时通知您更改。