[英]What are the key performance advantages of in-memory databases vs disk based NoSQL databases?
在阅读《设计数据密集型应用程序》一书时,我遇到了以下语句:
违反直觉的是,内存数据库的性能优势并不是由于它们不需要从磁盘读取而导致的。 如果您有足够的内存,即使是基于磁盘的存储引擎也可能永远不需要从磁盘读取数据,因为操作系统无论如何都会在内存中缓存最近使用的磁盘块。 相反,它们可以更快,因为它们可以避免以可写入磁盘的形式对内存中数据结构进行编码的开销。 透过窥镜的OLTP,以及我们在那发现的内容
所以我的问题是:
我对NoSQL领域还很陌生,所以如果我错过了什么,请一定要引导我正确的方向。
PS:我已经读了In内存数据库和磁盘内存数据库之间的区别,但是它没有解决我的特定问题。
我迅速测试了您的(1)。 这可能太天真了,但是它应该给出第一个答案,这更多的是鼓励您测试自己。
Redis setting
time: 4.391808
Redis getting: second run
time: 4.129066
Mongo setting
time: 30.313092
Mongo getting: second run
time: 33.969624
但是:REDIS和MongoDB是非常不同的系统,尚不清楚比较两者是否有用。 除非您实际遇到性能问题,否则请不要针对性能进行优化。
MongoDB是使用mongod --storageEngine wiredTiger --syncdelay 0 --journalCommitInterval 500 --dbpath /usr/local/var/mongodb
并且该计算机具有32GB RAM(=足以将所有数据保留在内存中)。
这是我使用的ruby脚本:
redis = Redis.current
redis.flushall
mongodb = Mongo::Client.new([ '127.0.0.1:27017' ], :database => 'test')
collection = mongodb[:mycollection]
collection.delete_many({})
collection.indexes.create_one(name: 1)
setids = (0..100000).to_a.map {|i| {name: "#plop_#{i}", val: i} }.shuffle
getids = (0..100000).to_a.map {|i| {name: "#plop_#{i}"} }.shuffle
puts "Redis setting"
time do
x = 0
setids.each do |i|
x += i[:val]
redis.set(i[:name], i[:val])
end
fail unless x == (0..100000).sum
end
["first", "second"].each do |run|
puts "Redis getting: #{run} run"
time do
x = 0
getids.each do |i|
x += r.get(i[:name]).to_i
end
fail unless x == (0..100000).sum
end
end
puts "Redis setting (hashes)"
redis.flushall
time do
x = 0
setids.each do |i|
x += i[:val]
redis.hset(i[:name],:val, i[:val])
end
fail unless x == (0..100000).sum
end
["first", "second"].each do |run|
puts "Redis getting (hashes): #{run} run"
time do
x = 0
getids.each do |i|
x += redis.hget(i[:name], :val).to_i
end
fail unless x == (0..100000).sum
end
end
puts "Mongo setting"
time do
x = 0
setids.each do |i|
x += i[:val]
collection.insert_one(i)
end
fail unless x == (0..100000).sum
end
["first", "second"].each do |run|
puts "Mongo getting: #{run} run"
time do
x = 0
getids.each do |i|
x += collection.find(i).first[:val]
end
fail unless x == (0..100000).sum
end
end
def time
start = Time.now
yield
puts "time: #{Time.now - start}"
end
全面披露:我代表eXtremeDB的供应商,eXtremeDB是最早的内存数据库系统之一(于2001年首次发布)。
不,它们是非常不同的DBMS,正如Matt的回答所证明的。
再说一次 无论是否异步,它仍然是一项系统活动,它将从原本是受CPU约束的系统中窃取CPU周期。 (我在这里假设内存数据库的性能是合理的,因此数据库活动非常激烈。)此外,基于磁盘的内存与内存数据库的DBMS处理事务原子性的方式是不同。 对于纯内存DBMS而言,它可能更简单,而对于提交事务的正常情况进行了优化。 在最佳情况下,我们可以就地更新数据,然后将之前的映像复制到回滚缓冲区。 如果事务提交,我们只丢弃回滚缓冲区。 因此,提交速度非常快,但中止会花费更多时间。 当您需要在并发访问设置(MVCC)中强制执行READ-COMMITTED时,事情就变得更加复杂。
否。任何基于磁盘的DBMS都不(无法)知道其数据已完全缓存。 它将始终遵循确定请求的页面是否在缓存中的逻辑。 那不是免费的(它使用CPU周期)。 真正的内存中DBMS没有这种查找逻辑,因此消除了这种处理。 此外,基于磁盘的DBMS使用较大的页面大小(通常是磁盘阻塞因子的倍数,因此是4K,8K,16K等),可以容纳许多记录/行/对象/文档/...。是否在缓存中,仍然有必要在页面上找到特定对象。 当然,这并不适用于每个DBMS-实现细节差异很大。 无论如何,内存数据库不关心磁盘阻塞因素,也不想浪费时间在页面上查找对象。 我们使用较小的页面大小来消除或大幅减少对象的页面内搜索。
同样,基于磁盘的数据库与内存中的DBMS实现索引的方式也非常不同。 无需赘述(请参见下面的白皮书),最终结果是,与内存数据库相比,对于具有相同行数的基于磁盘的数据库,b树更深。 或者,内存数据库可能总共使用不同类型的索引(t树或哈希)。 但是,让我们坚持使用b树。 较深的树的作用是使树行走以找到搜索值所需的平均级别和最坏情况级别更高。 最后,一旦找到了b树节点(等于数据库页面),就会使用二进制搜索来找到页面上的搜索值(插槽)。 在4K(或16K或...)的页面上进行二进制搜索比对数百个字节的页面进行更多的迭代。 同样,所有这些都归结为更多的CPU周期。
还有其他考虑。 请随时阅读我们的白皮书(免费访问,无需注册)“ 真正的IMDS请站起来吗? ”
和“ 内存数据库系统:神话与事实 ”。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.