写密集型功能的架构

时间:2016-06-24 11:44:48

标签: ruby oracle ruby-on-rails-3 caching memcached

我使用由Oracle数据库支持的Ruby on Rails和memcached用于我当前的项目。

有一个使用非常多的功能,它依赖于单个数据库视图作为数据源,并且此数据源内部具有其他数据库视图和表。

这是一个虚拟的数据库视图,能够从一个地方访问所有内容,而不是物化的数据库视图。

用户大部分时间都在他们想要更新的功能中,因此最新数据非常重要。

从此视图获取数据时,我将安全表内部连接到视图(安全表不是视图本身的一部分),其中包含一些我们用于在更细粒度级别上控制数据访问的字段。例如,安全表具有user_id, prop_1, prop_2列,其中prop_1, prop_2是db视图中可用的列,user_id是登录用户。有些用户在安全表中有相同的道具说prop_1 = 1 and prop_2 = 1,但也可以像其他用户一样拥有prop_1,但prop_2prop_1 = 2 and prop_2 = 1不同。 prop_1和prop_2有许多不同的组合,将它们视为另一个表的FK,因此可能有很多条目。

现在,在应用程序上检索记录的时间差不多是10秒,这很慢。我正在考虑替代方法。

我首先要看的是物化视图,但由于用户经常更新,因此可能不是最佳选择,因为刷新视图可能需要时间。

我想到的第二件事是缓存,使用prop_1prop_2组合作为基础数据的复合键,因为许多用户具有相同的组合,并且具有相同组合的任何人都可以访问相同的数据。

但是,这种方法可能需要更多的代码重写和逻辑来保存和检索片段中的数据,而不是像在数据库视图中那样使用一个查询从一个位置。

根据您的经验,您是如何解决相同/类似问题的?或者,我可以尝试一种更好的方法吗?

4 个答案:

答案 0 :(得分:1)

如果没有关于您观点的更多信息,很难给出一个好的答案,但我会尝试一下。

首先,我质疑使用单个非常复杂的视图。这很难调整,并且经常会导致性能问题,所以如果可以将它拆分成应用程序,这将是我的第一个赌注。

其次,您是否看过包含安全过滤器的查询的执行计划(解释计划)?它是否使用合理的索引?如果没有,请创建它们。也许安全属性没有编入索引,例如?

第三个选项可能是使用PL / SQL并调用与视图类似的存储过程。这使您可以更好地控制数据库,从而可以控制查询并将其拆分为多个步骤,但获得的结果与今天相同。

最后,您可以重写视图以获得更好的性能。一个经常被忽略的功能是WITH子句,它可以在主查询之前运行查询并将结果用作表。它帮助我大大提高了复杂视图的性能。

DBMS_RLS很酷但价格昂贵,它需要企业版,如果您还需要单独的许可证,我也不会感到惊讶。我会先找一个程序化的解决方案。

答案 1 :(得分:1)

如果你正在忍受可能导致你的数据库延迟的一些延迟,你可以将你的一些视图迁移到REDIS database(内存数据结构存储),这可能是最有效的...之一。读/写"密集的。

关于更新有问题,您可以实施websocket直接将精确更新扩散/推送给需要它的人。

我强调这种可能性需要对客户端和客户端进行一些修改。服务器端,但我认为这是保持最终用户视图以低延迟更新的最佳方法。

祝你好运

答案 2 :(得分:0)

多次加入复杂视图会出现性能问题。

您要限制的prop_1prop_2值是?也就是说,您是否将视图加入到这些列的安全性表中,例如

WHERE  my_view.prop_1 = security_table.prop_1
AND    my_view.prop_2 = security_table.prop_2
AND    security_table.user_id = :current_user_id

下一个问题:请prop_1prop_2映射到视图基础表中的列吗?如果是这样,它们是否可以用于快速访问基础表中的行 (在视图之外)?

如果是这样,我会尝试在基础表上使用DBMS_RLS.ADD_POLICY添加安全策略来强制执行您的安全性(即根据当前用户限制prop_1prop_2的值)和不要将安全表加入视图。

如果您向基础表添加安全策略,Oracle将在访问表时添加这些谓词,查询的复杂性开始之前。这可能会为Oracle的优化工具提供更快的流程所需的额外帮助。

如果没有看到您的代码,就很难说出更多。

答案 3 :(得分:0)

  

“依赖于单个数据库视图作为数据源,并且此数据源内部具有其他数据库视图和表。”

如果这是一个对象,我们称之为a God Object,这是一件坏事。它与数据库领域中的反模式一样多。在不知道细节的情况下很难确定,但可能你有一堆内连接,外连接和交叉连接,导致去规范化,数据重复和(可能)完整性问题。

当然,你有性能问题,这是不可避免的,因为这样的事情是无法调整的。无论您想要一行还是一万行,都是相同的查询。你没有给优化者做出合理决定的机会。

因此,您需要做的第一件事就是将此视图分解为映射到重点业务域的有意义的数据对象(视图或表)。您已经在使用Rails,管理更好的数据访问层应该不难。

至于安全性,Oracle确实有内置的虚拟专用数据库实现。如果您有Enterprise Edition,则应该使用DBMS_RLS来控制行级(和列级)访问。 RLS的主要优点是它不可见:在表或视图上设置策略,它会自动应用于在对象上执行的所有SQL。

如果您使用的是标准版,那么您将无法使用显式连接到您的安全表(但请参见下文)。

至于memcached的使用,根据我的经验,应用程序开发人员倾向于构建外部缓存,因为他们不了解Oracle数据库的工作方式,因此实现了糟糕的数据访问策略 - 例如通过单个怪物路由所有内容查看...

将DAL分解为离散的有意义的对象将为您提供更好的性能,因为数据库优化器将能够选择最有效的路径来提取所需的精确信息集。检索路径也会更好,因为热(最常查询)的块将在数据库缓冲区缓存中提供帮助,而目前我怀疑是由于全表扫描过多而完全被破坏。您可以利用服务器结果缓存,这可以帮助“用户具有相同的组合,[谁]可以访问相同的数据”Find out more

因此您可能会发现根本不需要外部缓存。当然,通过让数据库正确管理数据 - 适当地使用技术 - 您应该发现需要外部保存的数据少得多。您将应用程序描述为“密集写入”,因此您必须花费大量周期来保持缓存和数据库同步。显然,如果您正在处理Facebook数量的数据,您需要使用Facebook风格的数据管理方法。但一般来说,Do The Simplest Thing That Could Possibly Work仍然是最好的起点。