我正在尝试在Ruby中的Redis代码中优化ZRANGEBYSCORE。
具体来说,Redis网站(http://redis.io/commands/zrangebyscore)声明:
时间复杂度:O(log(N)+ M),其中N是元素的数量 排序集和M返回的元素数。如果M是 常数(例如总是要求LIMIT的前10个元素), 你可以认为它是O(log(N))。
所以,正如我读到的那样,只要我使用限制,大(O)应该在O(log(N)处保持不变,无论限制是设置为48还是6.但是,我的基准测试似乎另有建议。
require 'redis'
def bench(descr)
start = Time.now
yield
puts "#{descr} #{Time.now-start} seconds"
end
def with_pipelining_48
id = 26053643
@@redis.pipelined {
1000.times {
@@redis.zrevrangebyscore("key:#{id}", "+inf", "-inf", :limit => [0, 48],:with_scores => true)
}
}
end
def with_pipelining_24
id = 26053643
@@redis.pipelined {
1000.times {
@@redis.zrevrangebyscore("key:#{id}", "+inf", "-inf", :limit => [0, 24],:with_scores => true)
}
}
end
def with_pipelining_12
id = 26053643
@@redis.pipelined {
1000.times {
@@redis.zrevrangebyscore("key:#{id}", "+inf", "-inf", :limit => [0, 12],:with_scores => true)
}
}
end
def with_pipelining_6
id = 26053643
@@redis.pipelined {
1000.times {
@@redis.zrevrangebyscore("key:#{id}", "+inf", "-inf", :limit => [0, 6],:with_scores => true)
}
}
end
bench("with pipelining_48") {
with_pipelining_48
}
bench("with pipelining_24") {
with_pipelining_24
}
bench("with pipelining_12") {
with_pipelining_12
}
bench("with pipelining_6") {
with_pipelining_6
}
返回以下结果:
with pipelining_48 1.709097 seconds
with pipelining_24 0.930054 seconds
with pipelining_12 0.801045 seconds
with pipelining_6 0.633037 seconds
我的结果似乎与Redis文档不一致。有人可以说明可能导致分歧的原因。
答案 0 :(得分:1)
因此,首先,对于真正的基准测试,您应该在抛弃异常值后取平均值。所有这些操作之间的差异都是以毫秒为单位,所以如果你只是有一个微小的网络打嗝,或者你的盒子上发生了一些奇怪的事情,它就会把数字丢掉。如果你这样做,你的数字可能会有所不同。
其次,当您对Redis进行操作时,除了操作成本之外,还会发生更多事情。需要与Redis建立连接以及其他相关的启动成本。数据也需要传输,并且将来回进行网络传输。您的时间安排不仅仅是运营成本,还包括所有这些辅助成本。这些也将是非线性的,因为可以根据数据大小使用用于保持数据的不同格式。总而言之,要点是zrevrangebyscore
是O(log(n)+ m),但操作中也涉及辅助成本,并且运营成本低(几乎总是如此) Redis),这些成本使操作的实际成本相形见绌。这是一件好事。
答案 1 :(得分:0)
我相信你误解了Big(O)的含义。 Big(O)是一个复杂性度量,正如Redis的文档所述,通过保持M不变,你可以放弃它对复杂性的“贡献”(基本上,O(常数)= O(1))。这意味着如果你要比较这些操作,只要M保持不变,只有N起作用。
然而,这并不意味着性能是相同的。返回6个元素或24个不同,因为您正在移动不同数量的数据(无论复杂程度如何)。