2017-09-01 152 views
16

查询内存数据库表过程中我有一个不断变化,但很少访问的SQL表。出在支持高速缓存

表由用户ID分配,每个用户在所述表中的多个记录。

我想保存数据库资源并将此表更靠近某种内存缓存中的应用程序。

在过程缓存是太内存密集型所以它需要外部的应用程序。

像Redis这样的关键值存储由于Redis对表进行序列化和反序列化的开销而被证明效率低下。

我正在寻找可以将此表(或数据分区)存储在内存中的东西,但是让我仅查询我需要的信息,而无需为每次读取序列化和反序列化大块数据。

是否有任何内存数据库表中会提供Out of Process,以支持高速缓存查询?

搜索显示Apache Ignite可能是一个可能的选项,但我正在寻找更多的建议。

+0

你所说的“进程外的内存数据库表”呢? – Sameer

+0

你的前端是什么?一些像Asp.net这样的托管环境具有输出缓存或中间件缓存功能,如果符合您的需求,您还可以查看Elastic Search。我存储的数据为 –

回答

9

因为它是外的过程,它所要做的序列化和反序列化。您所关心的问题是如何减少序列化/反分类工作。如果您使用Redis'STRING类型,则无法减少这些工作。

但是,您可以使用HASH来解决问题:将您的SQL表映射到HASH

假设您有以下表格:person: id(varchar), name(varchar), age(int),您可以将人物id作为关键字,并以nameage作为字段。当你想搜索的人的名字,你只需要得到名称字段(HGET person-id name),其它字段将不会被反序列化。

+1

,每个用户需要缓存很多行。理想情况下,我想用UserId和TagId查询。每个用户都有许多不同的行,TagId不同。如果我可以从内存表中执行SQL类型查询并说出UserId = y和TagId = x,并且只返回包含数据的一行,那将是理想的。这就是我们如何使用SQL来存储和检索当前数据。 SQL hekaton听起来可能是可能的,但成本很高。 – SetiSeeker

4

对于您来说,Ignite确实是一种可行的解决方案,因为您可以通过使用内部二进制表示来访问对象字段来优化序列化/反序列化开销。你可以参考这个文档页面,了解更多信息:https://apacheignite.readme.io/docs/binary-marshaller

还访问开销可通过禁用优化副本上读选项https://apacheignite.readme.io/docs/performance-tips#section-do-not-copy-value-on-read

通过用户ID数据的搭配,也可以通过Ignite:https://apacheignite.readme.io/docs/affinity-collocation

2

正如@for_stack说,Hash将非常适合你的情况。

你说过,每个用户在db中索引的行数都是user_idtag_id。所以它是(user_id,tag_id)唯一指定一行。每一行的功能依赖于这个元组,你可以使用元组作为HASH KEY。

例如,如果你想保存行(USER_ID,TAG_ID,用户名,年龄),该值( “123456”, “FDSA”, “安区”,20)到Redis的,你可以这样做:

HMSET 123456:FDSA username "gsz" age 30 

当您想查询与USER_ID和TAG_ID的用户名,你可以这样做:

HGET 123456:FDSA username 

所以每一个散列键将是user_idtag_id组合,如果你想关键更具人性化,您可以添加前缀字符串,例如“USERINFO”。例如:USERINFO:123456:FDSA

但是如果你只想查询一个user_id并获得所有具有这个user_id的行,上面的这个方法是不够的。

你可以建立在Redis的的secondary indexes你HASH。

如上所述,我们使用user_id:tag_id作为HASH密钥。因为它可以唯一指向一行。如果我们想查询关于一个user_id的所有行。

我们可以使用sorted set建立一个二级索引,以便哈希存储有关此user_id的信息。

我们可以在SortedSet的补充一点:

ZADD user_index 0 123456:FDSA 

如上所述,我们设置了memberstring of HASH key,并设置score为0和规则是,我们应该将所有评分在这个zset到0,然后我们可以使用字典顺序来进行范围查询。请参阅zrangebylex

E.g.我们想要得到的所有行约USER_ID 123456,

ZRANGEBYLEX user_index [123456 (123457 

这将返回所有其前缀是123456的散列键,然后我们使用这个字符串作为散列关键字和hget或hmget检索信息来源,我们想要的东西。

[表示包含性,(表示排他性。以及为什么我们使用123457?这很明显。因此,当我们想要获取具有user_id的所有行时,我们应该指定使user_id字符串的最左端字符的ascii值加1的上限。

有关lex索引的更多信息,请参阅上文提到的文章。

1

对于一个只读工作负载MySQL MEMORY engine应该可以正常工作(编写DML锁定整个表)。这样你就不需要改变你的数据检索逻辑。

或者,如果您可以更改数据检索逻辑,那么Redis也是一个选项。要增加@GuangshengZuo描述的内容,有ReJSONRedis可动态加载的模块(用于Redis 4+),它在Redis之上实现文档存储。它可以进一步放宽网络上来回编组大型结构的要求。

1

只需6原则(这是我收集here),它是一个SQL头脑的人对自己适应Redis的方法非常简单。简单地说,他们是:

  1. 最重要的是,不要怕产生大量的键值对。所以请随意将表格的每一行存储在不同的密钥中。
  2. 使用Redis的哈希映射数据类型
  3. 表键从下表的主键的值由分隔的名称(如‘:’)
  4. 商店剩余的字段作为哈希
  5. 当你想查询单列,直接形成键,当你想要查询各种检索其结果
  6. ,使用野生字符“*”对你的关键。但请注意,扫描键会中断其他Redis进程。所以如果你真的需要使用这种方法。

该链接只是给出了一个简单的表格示例以及如何在Redis中对其进行建模。遵循这6条原则,您可以继续像普通表一样思考。 (当然,如果没有一些不那么相关概念CRUD,约束,关系等)使用内存缓存和Redis的组合对MYSQL的顶部