SQL数据库设计 - 缓存表?

时间:2010-09-22 07:23:07

标签: sqlite caching performance

在提高count(1)查询的性能时,数据库设计的常见/最佳做法是什么? (我目前正在使用SQLite

我已对数据进行了规范化,它存在于多个表中,而对于我想要在具有良好索引的单个表上执行的简单操作 - 查询对于我的目的而言是可接受的。

例如:

SELECT count(1) from actions where type='3' and area='5' and employee='2533';

但是当我开始进入多个表查询时,事情变得太慢(> 1秒)。

SELECT count(1) 
  from
  (SELECT SID from actions 
      where type='3' and employee='2533' 
   INTERSECT 
     SELECT SID from transactions where currency='USD') x;

我应该如何缓存结果?什么是好的设计? 我的自然反应是添加一个表,仅用于存储每个员工的缓存结果行?

1 个答案:

答案 0 :(得分:1)

修改

Command Query Responsibility Segregation (CQRS)等设计模式专门旨在提高数据访问的read side性能,通常是在分布式系统和企业范围内。

  • 发出命令以指示数据的“交易”或“更改/更新”
  • 当系统处理这些命令时(例如通过更新数据库表),受影响对象的新状态为“广播”
  • 感兴趣的系统(例如用户界面或可查询的REST API)将订阅这些数据更改,然后根据其特定需求“塑造”更新的数据
  • 然后缓存此更新数据(通常称为“读取存储”)

与CQRS通常相关的另一种模式是"Event Sourcing",它存储,然后允许“重播”命令,用于各种用例。

上述情况对您的方案可能过度,但在内部应用级别实施缓存非常简单,可以通过Sqllite Trigger

假设“读取”比写入actionstransactions表的次数多得多,

  • 您可以专门创建一个缓存表,专门用于“按员工划分的操作的SID”和一个用于“按货币划分的事务的SID”的缓存表,或者甚至将两者结合起来(取决于您查询的其他方案)
  • 每次基础actiontransactions表更新时,您都需要更新这些缓存表。一种廉价(和讨厌)的方法是在actiontransactions表上提供INSERT,UPDATE和DELETE触发器,然后更新相应的缓存表。
  • 您的“查询”界面现在主要使用“派生”数据(例如计数)与缓存表进行交互。
  • 但是,您仍然可能需要处理缓存未命中方案,例如这些缓存表的初始“种子”,或者是否需要重新生成缓存表。

除了像SqlLite这样的本地关系数据库之外,像MongoDb, Cassandra and Redis这样的NoSql数据库经常被用作读取繁重环境中读取端缓存的替代方法(取决于您的数据类型和格式)需要缓存)。但是,您需要处理将“master”(例如SQLLite)数据库中的数据同步到这些缓存读取存储的替代方法 - 触发器显然不会在此处删除它。

原始答案

如果您100%确定您始终为同一客户重复完全相同的查询,请务必保留结果。

但是,在大多数其他情况下,RDBMS通常可以很好地处理缓存。

与查询的INTERSECT

SELECT SID from transactions where currency='USD'

如果有大量有USD的交易记录,可能会出现问题。

可能你可以用连接替换它吗?

SELECT count(1) from 
(
    SELECT t.[SID] 
    from
        transactions as t
        inner join
        (
            SELECT SID from actions where type='3' and employee='2533'
        ) as a
        on t.SID = a.SID
    where t.currency= 'USD'
) as a

您可能只是检查索引:

有关

  • 从行动中选择count count(1) type ='3',area ='5'和 雇员= '2533'
  • 从行动中选择SID type ='3',employee ='2533'

Actions(Employee, Type)Actions(Employee, Type, Area)上的索引是有意义的(假设Employee具有最高的选择性,并且取决于类型和区域的选择性)。

您还可以将其与Actions(Employee,Type,Area,SID)上的索引进行比较,作为第二个查询的覆盖索引。

对于上面的联接,您需要Transactions(SID, Currency)

上的索引