【问题标题】:Why is SQLite faster than Redis in this simple benchmark?为什么在这个简单的基准测试中 SQLite 比 Redis 快?
【发布时间】:2012-06-26 22:07:41
【问题描述】:

我在本地机器上做了简单的性能测试,这是python脚本:

import redis
import sqlite3
import time

data = {}
N = 100000

for i in xrange(N):
    key = "key-"+str(i)
    value = "value-"+str(i)
    data[key] = value

r = redis.Redis("localhost", db=1)
s = sqlite3.connect("testDB")
cs = s.cursor()

try:
    cs.execute("CREATE TABLE testTable(key VARCHAR(256), value TEXT)")
except Exception as excp:
    print str(excp)
    cs.execute("DROP TABLE testTable")
    cs.execute("CREATE TABLE testTable(key VARCHAR(256), value TEXT)")

print "[---Testing SQLITE---]"
sts = time.time()
for key in data:
    cs.execute("INSERT INTO testTable VALUES(?,?)", (key, data[key]))
    #s.commit()
s.commit()
ste = time.time()
print "[Total time of sql: %s]"%str(ste-sts)

print "[---Testing REDIS---]"
rts = time.time()
r.flushdb()# for empty db
for key in data:
    r.set(key, data[key])
rte = time.time()
print "[Total time of redis: %s]"%str(rte-rts)

我希望 redis 执行得更快,但结果表明它要慢得多:

[---Testing SQLITE---]
[Total time of sql: 0.615846157074]
[---Testing REDIS---]
[Total time of redis: 10.9668009281]

那么,redis 是基于内存的,那么 sqlite 呢?为什么redis这么慢?什么时候需要使用redis,什么时候需要使用sqlite?

【问题讨论】:

  • 为什么 SQLite 会慢? ;-) 不要忘记,在这种情况下,SQLite 也是完全“进行中”(并且没有竞争)。另外,为什么要给flushdb 计时?
  • 听起来你已经阅读了太多 NoSQL 炒作。
  • @torayeff 您可以使用CREATE TABLE IF NOT EXISTS 进一步加快 sqlite 部分的速度,并且可以取出往返和 try/catch 块;)
  • “小。快。可靠。选择任何三个。”需要我们多说吗?
  • 嗯,内存中的数据不会持久化。如果您需要长时间保留它(或者它需要在崩溃中幸存下来),那么我建议您不要使用这种配置。我只是指出了在您的基准测试中进一步倾斜/调整/测试的方法。

标签: python sql sqlite redis


【解决方案1】:

来自redis documentation

Redis 是一个服务器:所有命令都涉及网络或 IPC 往返。将其与 SQLite、Berkeley DB、Tokyo/Kyoto Cabinet 等嵌入式数据存储进行比较是没有意义的……因为大多数操作的成本恰恰是由网络/协议管理主导的。

这确实是有道理的,尽管在某些情况下这是对速度问题的承认。例如,在多个并行访问下,Redis 的性能可能比 sqlite 好得多。

适合工作的正确工具,有时是 redis,有时是 sqlite,有时是完全不同的东西。如果此速度测试正确显示了您的应用程序将实际执行的操作,那么 sqlite 将为您提供更好的服务,并且您执行此基准测试很好。

【讨论】:

  • +1,虽然我当然不同意这句话:我通常不感兴趣 如何 某些东西的工作原理(好吧,但在基准测试时不感兴趣),但是手头的工作有多快——如果某件事由于某些架构决策而明显变慢,那仍然不会使比较“毫无意义”
  • 我是这句话的原作者,我不同意你的不同意见;-) 基准测试是比较苹果和苹果,所以你需要了解苹果是什么来评估它的性能。
  • 苹果到橙子,水果仍然是水果——你有一个目标要实现。它们是可比的。如何实现该目标的其他一切都是核心目标的语义。问题在于一种解决方案对另一种解决方案的性能和速度。如果您看得太接近细节,或者像您所说的那样,苹果与苹果之间的差异几乎可以忽略不计。
【解决方案2】:

目前的答案提供了关于 Redis 为何会失去此特定基准的洞察,即针对服务器执行的每个命令产生的网络开销,但尚未尝试重构基准代码以加速 Redis 性能。

你的代码有问题:

for key in data:
    r.set(key, data[key])

您需要与 Redis 服务器进行 100,000 次往返,从而导致巨大的 I/O 开销。

这是完全没有必要的,因为 Redis 为某些命令提供了类似“批处理”的功能,因此对于 SET 有 MSET,因此您可以将上述内容重构为:

r.mset(data)

从 100,000 次服务器跳闸次数减少到 1 次。您只需将 Python 字典作为单个参数传递,Redis 就会自动将更新应用到服务器上。

这将使您的特定基准测试完全不同,您应该会看到 Redis 的性能至少与 SQLite 相当。

【讨论】:

  • 这是一个真实的比较。
  • 好点。但是,如果您使用r.mset 将r.set 的循环替换为单个批量操作,那么在sqlite 端,您还需要将多个INSERT 语句的循环替换为单个批量INSERT。 IMO,只有这样它才是真正可靠的基准,可以比较两端的批量操作与批量操作。
【解决方案3】:

SQLite 非常快,您只需要一个 IO 操作(在 commit 上)。 Redis 在网络上执行的 IO 显着增加。更多的同类比较将涉及通过网络访问的关系数据库(如 MySQL 或 PostgreSQL)。

您还应该记住,SQLite 已经存在了很长时间并且是非常高度优化的。它受到ACID 合规性的限制,但您实际上可以turn that off(就像一些 NoSQL 解决方案所做的那样),并且更快地获得它。

【讨论】:

  • 这很公平,但开销应该很小,因为它是在本地主机上连接的。至少比跨网络的开销少。
  • @swasheck 是的,它没有连接到另一台机器那么糟糕,但它仍然涉及系统调用和更复杂的通信(与直接使用自己进程的内存相比)。
  • 如果我想在网络爬虫中检查 url-seen 并同时更新数据库,该怎么办?
  • 禁用“ACID”(例如刷新设置)对于合理的事务大小并不能加快 SQLite 的速度……只有“记住真的很重要”的提交。 (尽管还有其他问题可以确定交易的可见性。)
  • @pst those are both very good points which also serve to reinforce the need to truly know your project and select your tools appropriately.
【解决方案4】:

刚刚注意到您没有为 redis 提交提交。使用管道可以减少时间:

[---测试 SQLITE---]

[sql总时间:0.669369935989]

[---测试 REDIS---]

[redis总耗时:2.39369487762]

【讨论】:

  • +1 表示 sqlite 在流水线后仍然更快。顺便说一句,您还可以通过批量插入使 sqlite 更快。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-11-28
  • 1970-01-01
  • 2015-06-09
  • 2014-06-04
  • 1970-01-01
  • 1970-01-01
  • 2014-11-26
相关资源
最近更新 更多