对数据库中的数据进行缓存是一次性全部取出还是按需取出效率高呢?

时间:2020-11-27 07:59:21
环境:Java + Tomcat + Oracle
我们公司的开发框架有个叫做dict的基础服务,用于把数据库中保存的状态码“翻译”成用于显示的状态。
比如:0-有效,1-过期,2-失效这样的。
而数据库中有两张表专门用于保存这种转换关系

我看到公司的实现是在tomcat启动时就把dict表中所有数据全部读出,然后缓存成全局的键值对。

但是我在思考一个问题,由于dict中的记录有至少一半是千年都不一定用得上的,所以如果写个类用于缓存dict键值对,调用get时检查记录是否存在,如果不存在就查数据库取得之后返回
这样就能 只缓存用到过的数据了,但是这样却 导致查库的次数增加了(因为每次只取一条记录)

所以我很纠结哪种实现性能更好些呢?希望各位赐教

15 个解决方案

#1


如果有一半多的一般都用不到还是按需取,缓存常用的比较好吧

#2


取出常用的部分放在缓存中,并对数据库按照常用和不常用做一下索引排序,查找时先找缓存,找不到的时候在从数据库中按照不常用->常用找

#3


要么就做二级缓存,一级常用,二级不常用也可以,取决于你的数据量和不常用数据的占比

#4


引用 2 楼 sfgm521 的回复:
取出常用的部分放在缓存中,并对数据库按照常用和不常用做一下索引排序,查找时先找缓存,找不到的时候在从数据库中按照不常用->常用找


我也是这样做的

#5


关键是“常用”与“不常用”本身就是个模糊而无法界定的概念,某个功能客户用得多自然对应的dict也查找得多。这个不能主观推断。然而,如果按以上诸君说的,那岂不是还得统计查找量,得不偿失,本来就是为了减少数据库访问才缓存的。

我的意思也就是“常用”的和“不常用”的是完全混在一起的,我们无法把它们单独分拣出来,甚至连按常用的程度排序都不能。所以我们只能一视同仁的对待这些数据。在这样的情况下,是一次性全部进行缓存还是按需取出来缓存好些呢?前者可能浪费一些内存资源,后者可能使数据库访问次数增加。

#6


引用 3 楼 sfgm521 的回复:
要么就做二级缓存,一级常用,二级不常用也可以,取决于你的数据量和不常用数据的占比


常用的大约占百分之四五十吧,总共也就几千条记录。

#7


除了楼上的办法外,可以参考ibatis式的缓存方式。
ibatis的缓存设计是以SQL的hash值为KEY的,每个SQL第一次查询后结果会形成单独的缓存,SQL相同缓存就相同,SQL不同就算是同一张表也会读不同的缓存。
这种设计方式是典型的缓存冗余+按需获取,连缓存内的查询都不需要了,不过缺点也比较明显,为了防止缓存膨胀的太厉害,需要设定缓存上限和替换策略。

#8


楼上的说的我没听懂哦,这与sql语句有什么关联?况且我也不用考虑缓存上限和替换策略
不知是我没说清楚还是怎样,我打个比方:
比如我有一个dict{k,v}表,里面有几千条记录,因要频繁做依据k字段查v字段的操作所以考虑缓存
方案一相当于在tomcat启动时执行sql='select * from dict',然后把全部记录转化成一个hashmap,从此再也不查表。 优点:一共仅需查库一次;缺点:即使从未使用过的记录,也占用了内存。
方案二相当于我查找k=123的值时,先在hashmap中找有没有,如果有则直接返回,如果没有则执行sql='select * from dict where k=123',将结果放入缓存然后返回。 优点:仅缓存用过的记录;缺点:每次仅取一条记录,查库次数太多。

#9


顶~要六个字

#10


顶~~~顶~~~

#11


引用 5 楼 owen1759 的回复:
关键是“常用”与“不常用”本身就是个模糊而无法界定的概念,某个功能客户用得多自然对应的dict也查找得多。这个不能主观推断。然而,如果按以上诸君说的,那岂不是还得统计查找量,得不偿失,本来就是为了减少数据库访问才缓存的。

我的意思也就是“常用”的和“不常用”的是完全混在一起的,我们无法把它们单独分拣出来,甚至连按常用的程度排序都不能。所以我们只能一视同仁的对待这些数据。在这样的情况下,是一次性全部进行缓存还是按需取出来缓存好些呢?前者可能浪费一些内存资源,后者可能使数据库访问次数增加。
你可以增加一个字段来统计记录的读写次数,然后在分类

#12


内存调度算法

#13


To 11楼:
我在引文第一段最后一句已经说了,不统计读写次数,不进行分类。因为这样的做法是完全没有意义的,因为这根我的目的背道而驰了。

To 12楼:
没看懂哦~

#14


引用 2 楼 sfgm521 的回复:
取出常用的部分放在缓存中,并对数据库按照常用和不常用做一下索引排序,查找时先找缓存,找不到的时候在从数据库中按照不常用->常用找


+1

#15


键值对的数据在内存的占用本来就比较少,就算有个几万条,内存的使用量也就个几M;如果只是几千条的话,也就是k的数量级,直接放内存应该没什么问题的。。。

#1


如果有一半多的一般都用不到还是按需取,缓存常用的比较好吧

#2


取出常用的部分放在缓存中,并对数据库按照常用和不常用做一下索引排序,查找时先找缓存,找不到的时候在从数据库中按照不常用->常用找

#3


要么就做二级缓存,一级常用,二级不常用也可以,取决于你的数据量和不常用数据的占比

#4


引用 2 楼 sfgm521 的回复:
取出常用的部分放在缓存中,并对数据库按照常用和不常用做一下索引排序,查找时先找缓存,找不到的时候在从数据库中按照不常用->常用找


我也是这样做的

#5


关键是“常用”与“不常用”本身就是个模糊而无法界定的概念,某个功能客户用得多自然对应的dict也查找得多。这个不能主观推断。然而,如果按以上诸君说的,那岂不是还得统计查找量,得不偿失,本来就是为了减少数据库访问才缓存的。

我的意思也就是“常用”的和“不常用”的是完全混在一起的,我们无法把它们单独分拣出来,甚至连按常用的程度排序都不能。所以我们只能一视同仁的对待这些数据。在这样的情况下,是一次性全部进行缓存还是按需取出来缓存好些呢?前者可能浪费一些内存资源,后者可能使数据库访问次数增加。

#6


引用 3 楼 sfgm521 的回复:
要么就做二级缓存,一级常用,二级不常用也可以,取决于你的数据量和不常用数据的占比


常用的大约占百分之四五十吧,总共也就几千条记录。

#7


除了楼上的办法外,可以参考ibatis式的缓存方式。
ibatis的缓存设计是以SQL的hash值为KEY的,每个SQL第一次查询后结果会形成单独的缓存,SQL相同缓存就相同,SQL不同就算是同一张表也会读不同的缓存。
这种设计方式是典型的缓存冗余+按需获取,连缓存内的查询都不需要了,不过缺点也比较明显,为了防止缓存膨胀的太厉害,需要设定缓存上限和替换策略。

#8


楼上的说的我没听懂哦,这与sql语句有什么关联?况且我也不用考虑缓存上限和替换策略
不知是我没说清楚还是怎样,我打个比方:
比如我有一个dict{k,v}表,里面有几千条记录,因要频繁做依据k字段查v字段的操作所以考虑缓存
方案一相当于在tomcat启动时执行sql='select * from dict',然后把全部记录转化成一个hashmap,从此再也不查表。 优点:一共仅需查库一次;缺点:即使从未使用过的记录,也占用了内存。
方案二相当于我查找k=123的值时,先在hashmap中找有没有,如果有则直接返回,如果没有则执行sql='select * from dict where k=123',将结果放入缓存然后返回。 优点:仅缓存用过的记录;缺点:每次仅取一条记录,查库次数太多。

#9


顶~要六个字

#10


顶~~~顶~~~

#11


引用 5 楼 owen1759 的回复:
关键是“常用”与“不常用”本身就是个模糊而无法界定的概念,某个功能客户用得多自然对应的dict也查找得多。这个不能主观推断。然而,如果按以上诸君说的,那岂不是还得统计查找量,得不偿失,本来就是为了减少数据库访问才缓存的。

我的意思也就是“常用”的和“不常用”的是完全混在一起的,我们无法把它们单独分拣出来,甚至连按常用的程度排序都不能。所以我们只能一视同仁的对待这些数据。在这样的情况下,是一次性全部进行缓存还是按需取出来缓存好些呢?前者可能浪费一些内存资源,后者可能使数据库访问次数增加。
你可以增加一个字段来统计记录的读写次数,然后在分类

#12


内存调度算法

#13


To 11楼:
我在引文第一段最后一句已经说了,不统计读写次数,不进行分类。因为这样的做法是完全没有意义的,因为这根我的目的背道而驰了。

To 12楼:
没看懂哦~

#14


引用 2 楼 sfgm521 的回复:
取出常用的部分放在缓存中,并对数据库按照常用和不常用做一下索引排序,查找时先找缓存,找不到的时候在从数据库中按照不常用->常用找


+1

#15


键值对的数据在内存的占用本来就比较少,就算有个几万条,内存的使用量也就个几M;如果只是几千条的话,也就是k的数量级,直接放内存应该没什么问题的。。。