内存数据库是怎么保证数据持久性避孕套的

2添加评论分享收藏感谢收起在 SegmentFault,学习技能、解决问题
每个月,我们帮助 1000 万的开发者解决各种各样的技术问题。并助力他们在技术能力、职业生涯、影响力上获得提升。
问题对人有帮助,内容完整,我也想知道答案
问题没有实际价值,缺少关键内容,没有改进余地
1. 性能我们确实知道redis是个内存数据库,用于缓存会提高性能。但如果redsi和应用程序不在同一台服务器,那么网络IO不也需要时间吗?现实中确实有很多redis和应用程序不在一台服务器的现象,怎么解释呢?2. 必要性如果不是需要跨语言操作数据,仅仅是在内存中缓存的话。那么利用编程语言自身提供的数据类型不好吗?不也是在内存中吗?比如java,数据类型比redis的5种类型还丰富的多呢!只要一直保持引用,垃圾回收器就不会回收。所谓key-value内存数据库,用编程语言中的 变量名-变量值 做不一样吗?而且对于熟悉java的人来说,根本就不再需要学习redis,不挺好的吗?
来源: MongoDB 技术问答
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
1、多台服务器可以是内网啊。2、redis可以设置很大的内存的,也就说量上有可能java是达不到的3、还有就是redis可保持数据的持续性,比如你java如果重启了或者你的java需要重新发布,那内存中的数据岂不是不存在了,redis不存在这个问题。4、而且redis更可靠,redis的数据可以沉淀到硬盘,可以恢复的,那你的java内存中的东西怎么恢复。5、很简单的一个问题就是,比如session你存在内存中,也就是说如果你重新发布的话,所有的用户都要重新登录了,redis不会有这个问题的。6、再比如,如果你有N多G的热数据需要存放在内存中,以方便高效率的读取,难道你告诉我用java的内存吗。
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
1.应用场景不同导致redis可以有多种部署方式,本机还是跨机缓存是根据要解决的问题来看。比如业务程序是高cpu消耗的,部署的机器只需要一般的内存配置即可。缓存的数据又比较多,需要单独部署,甚至需要多台组成集群。又比如系统比较大以后,需要各种模块化,微服务化,每个服务都可以独立演进,计算和数据分离也是比较常见的方式。另外不用担心网络io带来的开销,在没有达到网络带宽瓶颈之前,网络io都不是问题,延迟在ms级别,很划算的。
2.redis作为缓存和kv数据库还有持久化功能,断电重启后还可以恢复。当然如果你只是需要缓存机制你可以选择自己编程维护一套缓存,看你自己的需要,代价就是你要自己实现缓存的机制,自动失效,缓存写满等等功能。
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
MongoDB也有纯内存存储引擎,也可以了解和试用。
Love MongoDB! Have Fun!
我很好奇,Redis的问题提交到了MongoDB的版面上,我附带告知MongoDB也有类似的纯内存存储引擎,会有朋友表示不乐意和减1。
------------------------华丽的分割符--------------------------------
MongoDB中文社区线下活动缤纷,请猛戳下方:
三月份杭州站在即!!! 感兴趣的朋友火速报名!!!
同步到新浪微博
分享到微博?
关闭理由:
删除理由:
忽略理由:
推广(招聘、广告、SEO 等)方面的内容
与已有问题重复(请编辑该提问指向已有相同问题)
答非所问,不符合答题要求
宜作评论而非答案
带有人身攻击、辱骂、仇恨等违反条款的内容
无法获得确切结果的问题
非开发直接相关的问题
非技术提问的讨论型问题
其他原因(请补充说明)
我要该,理由是:
在 SegmentFault,学习技能、解决问题
每个月,我们帮助 1000 万的开发者解决各种各样的技术问题。并助力他们在技术能力、职业生涯、影响力上获得提升。MemSQL:号称世界上最快的内存-关系型数据库 兼容MySQL但快30倍
发表于 17:04|
来源GigaOM|
作者Jordan Novet
摘要:MemSQL是一款内存数据库,它将SQL语句预编译为C++从而获得极速的执行效率。MemSQL宣称这是世界上最快的分布式关系型数据库,兼容MySQL但快30倍,能实现每秒150万次事务,但此产品也遭到Facebook MySQL工程师的吐槽。
内存数据库初创公司MemSQL最近开发出一个新的分布式数据库版本,在内存中不仅能够处理更大的数据集,而且同时保持了高速处理。在最新的版本中,用户将可以横跨多个商用节点(服务器)扩展MemSQL数据集,实现超大规模下完成大型负载。而在此之前的版本,MemSQL数据库被限制于在单一的主机上。该公司的联合创始人兼CEO Eric Frenkiel表示,新版本相较于老版本,可以扩展到更多的主机上。不仅如此,新版本还配备了MemSQL Watch仪表板来追踪监控数据库集群的性能表现。
MemSQL是一款内存数据库,它通过将数据存在内存中,将SQL语句预编译为C++而获得极速的执行效率。MemSQL宣称这是世界上最快的分布式关系型数据库,兼容MySQL但快30倍,能实现每秒150万次事务。
MemSQL由前Facebook工程师Eric Frenkiel和微软SQL Server高级工程师Nikita Shamgunov(CTO)联合创办,MemSQL的高性能数据库还参照了Facebook的脚本,有着强烈的Facebook印记。在2011年7月,MemSQL获得了Ashton
Kutcher、SV Angel、Paul Buchheit以及New Enterprise Associates等14家风投的青睐,融资210万美元。仅一年以后又再次获得了IA
Ventures和Digital Sky Technologies两家共计300万美元的风险投资。
从MemSQL官网上了解到,MemSQL具有以下几大特色:
无可比拟的效率:MemSQL执行效率比传统的基于磁盘的数据库要快30倍,它优于其他内存数据库,因为它将SQL语句预编译为C++。
强大的SQL执行能力:支持全功能的关系型数据库,开发者不必修改现有程序即可获得NoSQL键/值存储系统的效率。
横向和纵向扩展:MemSQL支持纵向扩展,CPU越好效率就越高;而且支持向多CPU扩展;此外,MemSQL还可与MySQL节点结合起来处理PB级的负载。
缺省支持数据持久性:MemSQL缺省支持数据从内存到磁盘/SSD的同步,保证数据的安全可靠。
简易安装:只需30秒即可完成安装并使用MemSQL,兼容MySQL,学习曲线平滑。
MemSQL的竞争对手
MemSQL面临着
的挑战,他们都宣称比SQL表现更强劲,都有一个熟谙数据库技术的创始团队。现今有很多NewSQL创新企业,包括VoltDB、NuoDB、
ScaleBase、Tokutek、JustOneDB和Clustrix,这些公司都表示能够帮助关系型数据库扩展规模,性能也比MySQL更好,而价格上也要比同类型的Oracle数据库便宜得多。
MemSQL背后的故事
在日-12月1日,Hadoop与大数据技术大会(HBTC 2012)在北京举办。MemSQL联合创始人兼CTO Nikita
Shamgunov受邀参加了这次大会,在主题论坛做了主题为“
”的演讲。他认为摩尔定律的时代已经结束。虽然现在在很多方面提升的速度已经放缓,然而在数据上摩尔定律依然存在。数据每18个月就会翻番,这就需要更多的技术来操作如此庞大的数据。在本次大会上,MemSQL进入了我们的视线,给我们留下了深刻的印象。
图:MemSQL联合创始人兼CTO Nikita Shamgunov
CSDN后续对MemSQL做了多次报道,《
》一文在网上引起了很大的反响,不过不久之后就有人表示不服,
,他认为MemSQL是由一群聪明的小伙儿鼓捣出来的,他们现在正在媒体和技术社区“兴风作浪”。Facebook的这位工程师认为,系统必须在完全不同的配置文件中运行。例如,用于数据缓冲的内存在MemSQL中本质上是解除绑定的,而InnoDB在MySQL5.5把它限制在了128MB,这是MySQL5.1默认设置的16倍。至于写入性能方面,MemSQL
能写出2G的快照日志,而InnoDB设置为10MB的事务日志,所以会更快地开始检查点。尽管如此,对于基准来说,稳定持久是最重要的。MemSQL宣称支持ACID,其中耐久性是最重要的一环。MySQL的InnoDB默认是很耐用的,如果事务返回为“同意”,就会在崩溃后刻到磁盘上。MemSQL默认也是很“耐久”的,它也会有一个事务日志,而这并不意味着跟磁盘有关。最后总结:MemSQL每秒持久事务比InnoDB慢500倍;MemSQL在做一些简单的读写查询时,比MySQL慢上千倍,也许是慢百万倍。(信息来源于CSDN网站报道)
在微博上,MemSQL也曾引起很多技术大牛的聚焦,
表示MemSQL是一种伪技术,老瓶子装新酒,并不是革命性的东西。很多人觉得需要更快的DB,实际上,他们需要的是写更有效率SQL语句的人。而
就认为:效率差1个数量级是很难通过写SQL来提升的,除非之前的SQL不是专业人士写的。
其实MemSQL最真实的情况,我们不得而知,或许真正使用过MemSQL的人才有最有发言权。今天MemSQL又推出了自己最新的分布式版本,未来的表现究竟如何,我们将拭目以待!(文/王鹏,审校/仲浩)。
相关文章阅读:
& 原文链接:
Cloud Edge:2013年国际“云先锋”系列报道
公司产品/方向
Jana Uhlig
$ 1M (B)
实时Hadoop系统
Gleb Budman
开源存储硬件
Jennifer Medberry
$2.8M(A)
Kickboard(数据分析)
Shay Banon
$24 M(B)
开源搜索引擎
Jeff Tegethoff
$6M &(B)
企业内部部署IaaS平台
Craig Elliott
$20 M(B)
软件定义网络(SDN)
Joe Arnold
$6.1M(A)
软件定义存储
Adina Mangubat
DNA序列数据分析平台
Geoffrey Hinton
Jim Melvin&
$16M(C)&
应用性能管理(APM)
Chris K. Wensel
Java大数据框架
John Marshall
$200M(A)&
移动设备管理
Robert Drost
$44M(C)&
虚拟化网络
Narges Bani Asadi
&$6.5M(B)
基因测序平台
Albert Azout
数据预测分析
&$5.7M(A)
数据库虚拟化引擎
Dan Siroker
&$28M(A)
A/B 测试服务
Manav Mital
&$17M(B)
Matthew Prince
&$20M(B)
云安全、网络性能
Ted Schlein
&$9.4M(A)
Eric Frenkiel
备注:日更新,持续更新中......
”将于-7日在北京国家会议中心隆重举行。猛击!
相关活动已经火热启动:
,欢迎研发者、团队和创业企业参加!
本文为CSDN编译整理,未经允许不得转载。如需转载请联系
推荐阅读相关主题:
CSDN官方微信
扫描二维码,向CSDN吐槽
微信号:CSDNnews
相关热门文章Python内存数据库/引擎 - Python - 伯乐在线
& Python内存数据库/引擎
在平时的开发工作中,我们可能会有这样的需求:我们希望有一个内存数据库或者数据引擎,用比较Pythonic的方式进行数据库的操作(比如说插入和查询)。
举个具体的例子,分别向数据库db中插入两条数据,”a=1, b=1″ 和 “a=1, b=2”, 然后想查询a=1的数据可能会使用这样的语句db.query(a=1),结果就是返回前面插入的两条数据; 如果想查询a=1, b=2的数据,就使用这样的语句db.query(a=1, b=2),结果就返回前面的第二条数据。
那么是否拥有实现上述需求的现成的第三方库呢?几经查找,发现能够满足这样的需求。其实,PyDbLite和Python自带的SQLite均支持内存数据库模式,只是前者是Pythonic的用法,而后者则是典型的SQL用法。
他们具体的用法是这样的:
import pydblite
# 使用内存数据库
pydb = pydblite.Base(':memory:')
# 创建a,b,c三个字段
pydb.create('a', 'b', 'c')
# 为字段a,b创建索引
pydb.create_index('a', 'b')
# 插入一条数据
pydb.insert(a=-1, b=0, c=1)
# 查询符合特定要求的数据
results = pydb(a=-1, b=0)
1234567891011
import pydblite# 使用内存数据库pydb = pydblite.Base(':memory:')# 创建a,b,c三个字段pydb.create('a', 'b', 'c')# 为字段a,b创建索引pydb.create_index('a', 'b')# 插入一条数据pydb.insert(a=-1, b=0, c=1)# 查询符合特定要求的数据results = pydb(a=-1, b=0)
import sqlite3
# 使用内存数据库
con = sqlite3.connect(':memory:')
# 创建a,b,c三个字段
cur = con.cursor()
cur.execute('create table test (a char(256), b char(256), c char(256));')
# 为字段a,b创建索引
cur.execute('create index a_index on test(a)')
cur.execute('create index b_index on test(b)')
# 插入一条数据
cur.execute('insert into test values(?, ?, ?)', (-1,0,1))
# 查询符合特定要求的数据
cur.execute('select * from test where a=? and b=?',(-1, 0))
12345678910111213
import sqlite3# 使用内存数据库con = sqlite3.connect(':memory:')# 创建a,b,c三个字段cur = con.cursor()cur.execute('create table test (a char(256), b char(256), c char(256));')# 为字段a,b创建索引cur.execute('create index a_index on test(a)')cur.execute('create index b_index on test(b)')# 插入一条数据cur.execute('insert into test values(?, ?, ?)', (-1,0,1))# 查询符合特定要求的数据cur.execute('select * from test where a=? and b=?',(-1, 0))
2 pydblite和sqlite的性能
毫无疑问,pydblite的使用方式非常地Pythonic,但是它的效率如何呢?由于我们主要关心的是数据插入和查询速度,所以不妨仅对这两项做一个对比。写一个简单的测试脚本:
import time
count = 100000
def timeit(func):
def wrapper(*args, **kws):
t = time.time()
func(*args)
print time.time() - t, kws['des']
return wrapper
def test_insert(mdb, des=''):
for i in xrange(count):
mdb.insert(a=i-1, b=i, c=i+1)
def test_query_object(mdb, des=''):
for i in xrange(count):
c = mdb(a=i-1, b=i)
def test_sqlite_insert(cur, des=''):
for i in xrange(count):
cur.execute('insert into test values(?, ?, ?)', (i-1, i, i+1))
def test_sqlite_query(cur, des=''):
for i in xrange(count):
cur.execute('select * from test where a=? and b=?', (i-1, i))
print '-------pydblite--------'
import pydblite
pydb = pydblite.Base(':memory:')
pydb.create('a', 'b', 'c')
pydb.create_index('a', 'b')
test_insert(pydb, des='insert')
test_query_object(pydb, des='query, object call')
print '-------sqlite3--------'
import sqlite3
con = sqlite3.connect(':memory:')
cur = con.cursor()
cur.execute('create table test (a char(256), b char(256), c char(256));')
cur.execute('create index a_index on test(a)')
cur.execute('create index b_index on test(b)')
test_sqlite_insert(cur, des='insert')
test_sqlite_query(cur, des='query')
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
import timecount = 100000&def timeit(func):&&&&def wrapper(*args, **kws):&&&&&&&&t = time.time()&&&&&&&&func(*args)&&&&&&&&print time.time() - t, kws['des']&&&&return wrapper&@timeitdef test_insert(mdb, des=''):&&&&for i in xrange(count):&&&&&&&&mdb.insert(a=i-1, b=i, c=i+1)&@timeitdef test_query_object(mdb, des=''):&&&&for i in xrange(count):&&&&&&&&c = mdb(a=i-1, b=i)&@timeitdef test_sqlite_insert(cur, des=''):&&&&for i in xrange(count):&&&&&&&&cur.execute('insert into test values(?, ?, ?)', (i-1, i, i+1))&@timeitdef test_sqlite_query(cur, des=''):&&&&for i in xrange(count):&&&&&&&&cur.execute('select * from test where a=? and b=?', (i-1, i))&print '-------pydblite--------'import pydblitepydb = pydblite.Base(':memory:')pydb.create('a', 'b', 'c')pydb.create_index('a', 'b')test_insert(pydb, des='insert')test_query_object(pydb, des='query, object call')&&print '-------sqlite3--------'import sqlite3con = sqlite3.connect(':memory:')cur = con.cursor()cur.execute('create table test (a char(256), b char(256), c char(256));')cur.execute('create index a_index on test(a)')cur.execute('create index b_index on test(b)')test_sqlite_insert(cur, des='insert')test_sqlite_query(cur, des='query')
在创建索引的情况下,10w次的插入和查询的时间如下:
-------pydblite--------
0. query, object call
-------sqlite3--------
-------pydblite--------1. insert0. query, object call-------sqlite3--------0. insert0. query
在未创建索引的情况(把创建索引的测试语句注释掉)下,1w次的插入和查询时间如下:
-------pydblite--------
0.8 insert
5. query, object call
-------sqlite3--------
0.7 insert
-------pydblite--------0.8 insert5. query, object call-------sqlite3--------0.7 insert7. query
我们不难得出如下结论:
sqlite的插入速度是pydblite的3-5倍;而在建立索引的情况下,sqlite的查询速度和pydblite相当;在未建立索引的情况下,sqlite的查询速度比pydblite慢1.5倍左右。
我们的目标非常明确,使用Pythonic的内存数据库,提高插入和查询效率,而不考虑持久化。那么能否既拥有pydblite的pythonic的使用方式,又同时具备pydblite和sqlite中插入和查询速度快的那一方的速度?针对我们的目标,看看能否对pydblite做一些优化。
阅读pydblite的源码,首先映入眼帘的是对python2和3做了一个简单的区分。给外部调用的Base基于_BasePy2或者_BasePy3,它们仅仅是在__iter__上有细微差异,最终调用的是_Base这个类。
class _BasePy2(_Base):
def __iter__(self):
"""Iteration on the records"""
return iter(self.records.itervalues())
class _BasePy3(_Base):
def __iter__(self):
"""Iteration on the records"""
return iter(self.records.values())
if sys.version_info[0] == 2:
Base = _BasePy2
Base = _BasePy3
1234567891011121314151617
class _BasePy2(_Base):&&&&&def __iter__(self):&&&&&&&&"""Iteration on the records"""&&&&&&&&return iter(self.records.itervalues())&&class _BasePy3(_Base):&&&&&def __iter__(self):&&&&&&&&"""Iteration on the records"""&&&&&&&&return iter(self.records.values())&if sys.version_info[0] == 2:&&&&Base = _BasePy2else:&&&&Base = _BasePy3
然后看下_Base的构造函数,做了简单的初始化文件的操作,由于我们就是使用内存数据库,所以文件相关的内容完全可以抛弃。
class _Base(object):
def __init__(self, path, protocol=pickle.HIGHEST_PROTOCOL, save_to_file=True,
sqlite_compat=False):
"""protocol as defined in pickle / pickle.
Defaults to the highest protocol available.
For maximum compatibility use protocol = 0
self.path = path
"""The path of the database in the file system"""
self.name = os.path.splitext(os.path.basename(path))[0]
"""The basename of the path, stripped of its extension"""
self.protocol = protocol
self.mode = None
if path == ":memory:":
save_to_file = False
self.save_to_file = save_to_file
self.sqlite_compat = sqlite_compat
self.fields = []
"""The list of the fields (does not include the internal
fields __id__ and __version__)"""
# if base exists, get field names
if save_to_file and self.exists():
if protocol == 0:
_in = open(self.path)
# don't specify binary mode !
_in = open(self.path, 'rb')
self.fields = pickle.load(_in)
1234567891011121314151617181920212223242526272829
class _Base(object):&&&&&def __init__(self, path, protocol=pickle.HIGHEST_PROTOCOL, save_to_file=True,&&&&&&&&&&&&&&&& sqlite_compat=False):&&&&&&&&"""protocol as defined in pickle / pickle.&&&&&&&&Defaults to the highest protocol available.&&&&&&&&For maximum compatibility use protocol = 0&&&&&&&&&"""&&&&&&&&self.path = path&&&&&&&&"""The path of the database in the file system"""&&&&&&&&self.name = os.path.splitext(os.path.basename(path))[0]&&&&&&&&"""The basename of the path, stripped of its extension"""&&&&&&&&self.protocol = protocol&&&&&&&&self.mode = None&&&&&&&&if path == ":memory:":&&&&&&&&&&&&save_to_file = False&&&&&&&&self.save_to_file = save_to_file&&&&&&&&self.sqlite_compat = sqlite_compat&&&&&&&&self.fields = []&&&&&&&&"""The list of the fields (does not include the internal&&&&&&&&fields __id__ and __version__)"""&&&&&&&&# if base exists, get field names&&&&&&&&if save_to_file and self.exists():&&&&&&&&&&&&if protocol == 0:&&&&&&&&&&&&&&&&_in = open(self.path)&&# don't specify binary mode !&&&&&&&&&&&&else:&&&&&&&&&&&&&&&&_in = open(self.path, 'rb')&&&&&&&&&&&&self.fields = pickle.load(_in)
紧接着比较重要的是create(创建字段)、create_index(创建索引)两个函数:
def create(self, *fields, **kw):
Create a new base with specified field names.
- *fields (str): The field names to create.
- mode (str): the mode used when creating the database.
- if mode = 'create' : create a new base (the default value)
- if mode = 'open' : open the existing base, ignore the fields
- if mode = 'override' : erase the existing base and create a
new one with the specified fields
- the database (self).
self.mode = kw.get("mode", 'create')
if self.save_to_file and os.path.exists(self.path):
if not os.path.isfile(self.path):
raise IOError("%s exists and is not a file" % self.path)
elif self.mode is 'create':
raise IOError("Base %s already exists" % self.path)
elif self.mode == "open":
return self.open()
elif self.mode == "override":
os.remove(self.path)
raise ValueError("Invalid value given for 'open': '%s'" % open)
self.fields = []
self.default_values = {}
for field in fields:
if type(field) is dict:
self.fields.append(field["name"])
self.default_values[field["name"]] = field.get("default", None)
elif type(field) is tuple:
self.fields.append(field[0])
self.default_values[field[0]] = field[1]
self.fields.append(field)
self.default_values[field] = None
self.records = {}
self.next_id = 0
self.indices = {}
self.commit()
return self
def create_index(self, *fields):
Create an index on the specified field names
An index on a field is a mapping between the values taken by the field
and the sorted list of the ids of the records whose field is equal to
this value
For each indexed field, an attribute of self is created, an instance
of the class Index (see above). Its name it the field name, with the
prefix _ to avoid name conflicts
- fields (list): the fields to index
reset = False
for f in fields:
if f not in self.fields:
raise NameError("%s is not a field name %s" % (f, self.fields))
# initialize the indices
if self.mode == "open" and f in self.indices:
reset = True
self.indices[f] = {}
for _id, record in self.records.items():
# use bisect to quickly insert the id in the list
bisect.insort(self.indices[f].setdefault(record[f], []), _id)
# create a new attribute of self, used to find the records
# by this index
setattr(self, '_' + f, Index(self, f))
self.commit()
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
&&&&def create(self, *fields, **kw):&&&&&&&&"""&&&&&&&&Create a new base with specified field names.&&&&&&&&&Args:&&&&&&&&&&&&- *fields (str): The field names to create.&&&&&&&&&&&&- mode (str): the mode used when creating the database.&&&&&&&&&- if mode = 'create' : create a new base (the default value)&&&&&&&&- if mode = 'open' : open the existing base, ignore the fields&&&&&&&&- if mode = 'override' : erase the existing base and create a&&&&&&&&&&new one with the specified fields&&&&&&&&&Returns:&&&&&&&&&&&&- the database (self).&&&&&&&&"""&&&&&&&&self.mode = kw.get("mode", 'create')&&&&&&&&if self.save_to_file and os.path.exists(self.path):&&&&&&&&&&&&if not os.path.isfile(self.path):&&&&&&&&&&&&&&&&raise IOError("%s exists and is not a file" % self.path)&&&&&&&&&&&&elif self.mode is 'create':&&&&&&&&&&&&&&&&raise IOError("Base %s already exists" % self.path)&&&&&&&&&&&&elif self.mode == "open":&&&&&&&&&&&&&&&&return self.open()&&&&&&&&&&&&elif self.mode == "override":&&&&&&&&&&&&&&&&os.remove(self.path)&&&&&&&&&&&&else:&&&&&&&&&&&&&&&&raise ValueError("Invalid value given for 'open': '%s'" % open)&&&&&&&&&self.fields = []&&&&&&&&self.default_values = {}&&&&&&&&for field in fields:&&&&&&&&&&&&if type(field) is dict:&&&&&&&&&&&&&&&&self.fields.append(field["name"])&&&&&&&&&&&&&&&&self.default_values[field["name"]] = field.get("default", None)&&&&&&&&&&&&elif type(field) is tuple:&&&&&&&&&&&&&&&&self.fields.append(field[0])&&&&&&&&&&&&&&&&self.default_values[field[0]] = field[1]&&&&&&&&&&&&else:&&&&&&&&&&&&&&&&self.fields.append(field)&&&&&&&&&&&&&&&&self.default_values[field] = None&&&&&&&&&self.records = {}&&&&&&&&self.next_id = 0&&&&&&&&self.indices = {}&&&&&&&&self.commit()&&&&&&&&return self&&&&&def create_index(self, *fields):&&&&&&&&"""&&&&&&&&Create an index on the specified field names&&&&&&&&&An index on a field is a mapping between the values taken by the field&&&&&&&&and the sorted list of the ids of the records whose field is equal to&&&&&&&&this value&&&&&&&&&For each indexed field, an attribute of self is created, an instance&&&&&&&&of the class Index (see above). Its name it the field name, with the&&&&&&&&prefix _ to avoid name conflicts&&&&&&&&&Args:&&&&&&&&&&&&- fields (list): the fields to index&&&&&&&&"""&&&&&&&&reset = False&&&&&&&&for f in fields:&&&&&&&&&&&&if f not in self.fields:&&&&&&&&&&&&&&&&raise NameError("%s is not a field name %s" % (f, self.fields))&&&&&&&&&&&&# initialize the indices&&&&&&&&&&&&if self.mode == "open" and f in self.indices:&&&&&&&&&&&&&&&&continue&&&&&&&&&&&&reset = True&&&&&&&&&&&&self.indices[f] = {}&&&&&&&&&&&&for _id, record in self.records.items():&&&&&&&&&&&&&&&&# use bisect to quickly insert the id in the list&&&&&&&&&&&&&&&&bisect.insort(self.indices[f].setdefault(record[f], []), _id)&&&&&&&&&&&&# create a new attribute of self, used to find the records&&&&&&&&&&&&# by this index&&&&&&&&&&&&setattr(self, '_' + f, Index(self, f))&&&&&&&&if reset:&&&&&&&&&&&&self.commit()
可以看出,pydblite在内存中维护了一个名为records的字典变量,用来存放一条条的数据。它的key是内部维护的id,从0开始自增;而它的value则是用户插入的数据,为了后续查询和记录的方便,这里在每条数据中额外又加入了__id__和__version__。其次,内部维护的indices字典变量则是是个索引表,它的key是字段名,而value则是这样一个字典:其key是这个字段所有已知的值,value是这个值所在的那条数据的id。
举个例子,假设我们插入了“a=-1,b=0,c=1”和“a=0,b=1,c=2”两条数据,那么records和indices的内容会是这样的:
{0: {'__id__': 0, '__version__': 0, 'a': -1, 'b': 0, 'c': 1},
1: {'__id__': 1, '__version__': 0, 'a': 0, 'b': 1, 'c': 2}}
{'a': {-1: [0], 0: [1]}, 'b': {0: [0], 1: [1]}}
# records{0: {'__id__': 0, '__version__': 0, 'a': -1, 'b': 0, 'c': 1}, 1: {'__id__': 1, '__version__': 0, 'a': 0, 'b': 1, 'c': 2}}&# indices{'a': {-1: [0], 0: [1]}, 'b': {0: [0], 1: [1]}}
比方说现在我们想查找a=0的数据,那么就会在indices中找key为’a’的value,即{-1: set([0]), 0: set([1])},然后在这里面找key为0的value,即[1],由此我们直到了我们想要的这条数据它的id是1(也可能会有多个);假设我们对数据还有其他要求比如a=0,b=1,那么它会继续上述的查找过程,找到a=0和b=1分别对应的ids,做交集,就得到了满足这两个条件的ids,然后再到records里根据ids找到所有对应的数据。
明白了原理,我们再看看有什么可优化的地方:
数据结构,整体的records和indeices数据结构已经挺精简了,暂时不需要优化。其中的__version__可以不要,因为我们并不关注这个数据被修改了几次。其次是由于indices中最终的ids是个list,在查询和插入的时候会比较慢,我们知道内部维护的id一定是唯一的,所以这里改成set会好一些。
python语句,不难看出,整个_Base为了同时兼容python2和python3,不得不使用了2和3都支持的语句,这就导致在部分语句上针对特定版本的python就会造成浪费或者说是性能开销。比如说,d是个字典,那么为了同事兼容python2和3,作者使用了类似与for key in d.keys()这样的语句,在python2中,d.keys()会首先产生一个list,用d.iterkeys是个更明智的方案。再如,作者会使用类似set(d.keys()) – set([1])这样的语句,但是python2中,使用d.viewkeys() – set([1])效率将会更高,因为它不需要将list转化成set。
对特定版本python的优化语句就不一一举例,概括地说,从数据结构,python语句以及是否需要某些功能等方面可以对pydblite做进一步的优化。前面只是说了create和create_index两个函数,包括insert和__call__的优化也十分类似。此外,用普通方法来代替魔法方法,也能稍微提升下效率,所以在后续的优化中将__call__改写为了query。
优化后的代码,请见。
4 memlite、pydblite和sqlite的性能
让我们在上文的测试代码中加入对memlite的测试:
def test_query_method(mdb, des=''):
for i in xrange(count):
c = mdb.query(a=i-1, b=i)
print '-------memlite-------'
import memlite
db = memlite.Base()
db.create('a', 'b', 'c')
db.create_index('a', 'b')
test_insert(db, des='insert')
test_query_method(db, des='query, method call')
123456789101112
@timeitdef test_query_method(mdb, des=''):&&&&for i in xrange(count):&&&&&&&&c = mdb.query(a=i-1, b=i)&print '-------memlite-------'import memlitedb = memlite.Base()db.create('a', 'b', 'c')db.create_index('a', 'b')test_insert(db, des='insert')test_query_method(db, des='query, method call')
在创建索引的情况下,10w次的插入和查询的时间如下:
-------memlite-------
0. query, method call
-------pydblite--------
0. query, object call
-------sqlite3--------
-------memlite-------0. insert0. query, method call-------pydblite--------1. insert0. query, object call-------sqlite3--------0. insert0. query
在未创建索引的情况(把创建索引的测试语句注释掉)下,1w次的插入和查询时间如下:
-------memlite-------
0.4 insert
5. query, method call
-------pydblite--------
0.1 insert
4. query, object call
-------sqlite3--------
0.3 insert
-------memlite-------0.4 insert5. query, method call-------pydblite--------0.1 insert4. query, object call-------sqlite3--------0.3 insert7. query
可以看出,在创建索引的情况下,memlite的插入和查询性能在sqlite和pydblite之上;而在未创建索引的情况下,memlite的插入性能和sqlite一样,好于pydblite,memlite的查询性能比pydblite稍差,但好于sqlite。综合来看,memlite即拥有pydblite的pythonic的使用方式,又拥有pydblite和sqlite中性能较高者的效率,符合预期的优化目标。
关于作者:

我要回帖

更多关于 注重数据的持久性 的文章

 

随机推荐