键:Python 中的值存储可能有 100 GB 的数据,没有客户端/服务器

新手上路,请多包涵

There are many solutions to serialize a small dictionary: json.loads / json.dumps , pickle , shelve , ujson ,甚至通过使用 sqlite

但是当处理可能有 100 GB 的数据时,就不可能再使用这样的模块,因为在关闭/序列化时可能会重写整个数据。

redis 不是真正的选择,因为它使用客户端/服务器方案。

问题: 哪个键值存储、无服务器、能够处理 100+ GB 的数据,在 Python 中经常使用?

我正在寻找具有标准“Pythonic”的解决方案 d[key] = value 语法:

 import mydb
d = mydb.mydb('myfile.db')
d['hello'] = 17          # able to use string or int or float as key
d[183] = [12, 14, 24]    # able to store lists as values (will probably internally jsonify it?)
d.flush()                # easy to flush on disk

注意: BsdDB (BerkeleyDB) 似乎已被弃用。似乎有一个 LevelDB for Python ,但它似乎并不为人所知——而且我 还没有找到 可以在 Windows 上使用的版本。哪些是最常见的?


相关问题: Use SQLite as a key:value store , Flat file NoSQL solution

原文由 Basj 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 752
2 个回答

您可以使用 sqlitedict ,它为 SQLite 数据库提供键值接口。

SQLite 限制页面 表示理论最大值为 140 TB,具体取决于 page_sizemax_page_count 。但是,Python 3.5.2-2ubuntu0~16.04.4 ( sqlite3 2.6.0) 的默认值为 page_size=1024max_page_count=1073741823 这提供了约 1100 GB 的最大数据库大小,可以满足您的要求。

您可以像这样使用包:

 from sqlitedict import SqliteDict

mydict = SqliteDict('./my_db.sqlite', autocommit=True)
mydict['some_key'] = any_picklable_object
print(mydict['some_key'])
for key, value in mydict.items():
    print(key, value)
print(len(mydict))
mydict.close()

更新

关于内存使用。 SQLite 不需要你的数据集来适应 RAM。默认情况下,它最多缓存 cache_size 页面,这几乎是 2MiB(与上面相同的 Python)。这是您可以用来检查您的数据的脚本。运行前:

 pip install lipsum psutil matplotlib psrecord sqlitedict

sqlitedct.py

 #!/usr/bin/env python3

import os
import random
from contextlib import closing

import lipsum
from sqlitedict import SqliteDict

def main():
    with closing(SqliteDict('./my_db.sqlite', autocommit=True)) as d:
        for _ in range(100000):
            v = lipsum.generate_paragraphs(2)[0:random.randint(200, 1000)]
            d[os.urandom(10)] = v

if __name__ == '__main__':
    main()

./sqlitedct.py & psrecord --plot=plot.png --interval=0.1 $! 一样运行它。在我的例子中,它产生了这个图表: 图表

和数据库文件:

 $ du -h my_db.sqlite
84M my_db.sqlite

原文由 saaj 发布,翻译遵循 CC BY-SA 3.0 许可协议

LMDB (闪电内存映射数据库)是一种非常快速的键值存储,它具有 Python 绑定 并且可以轻松处理巨大的数据库文件。

还有 lmdbm 包装器,它提供 Pythonic d[key] = value 语法。

默认情况下它只支持字节值,但它可以很容易地扩展为对其他类型的值使用序列化程序(json、msgpack、pickle)。

 import json
from lmdbm import Lmdb

class JsonLmdb(Lmdb):
  def _pre_key(self, value):
    return value.encode("utf-8")
  def _post_key(self, value):
    return value.decode("utf-8")
  def _pre_value(self, value):
    return json.dumps(value).encode("utf-8")
  def _post_value(self, value):
    return json.loads(value.decode("utf-8"))

with JsonLmdb.open("test.db", "c") as db:
  db["key"] = {"some": "object"}
  obj = db["key"]
  print(obj["some"])  # prints "object"


一些基准。批量插入(每个 1000 个项目)用于 lmdbm 和 sqlitedict。对于这些非批量插入,写入性能会受到很大影响,因为默认情况下每个插入都会打开一个新事务。 dbm 指的是标准库 dbm.dumb。在 Win 7、Python 3.8、SSD 上测试。

秒级连续写入

| items | lmdbm | pysos |sqlitedict|   dbm   |
|------:|------:|------:|---------:|--------:|
|     10| 0.0000| 0.0000|   0.01600|  0.01600|
|    100| 0.0000| 0.0000|   0.01600|  0.09300|
|   1000| 0.0320| 0.0460|   0.21900|  0.84200|
|  10000| 0.1560| 2.6210|   2.09100|  8.42400|
| 100000| 1.5130| 4.9140|  20.71700| 86.86200|
|1000000|18.1430|48.0950| 208.88600|878.16000|

数秒内随机读取

| items | lmdbm | pysos |sqlitedict|  dbm   |
|------:|------:|------:|---------:|-------:|
|     10| 0.0000|  0.000|    0.0000|  0.0000|
|    100| 0.0000|  0.000|    0.0630|  0.0150|
|   1000| 0.0150|  0.016|    0.4990|  0.1720|
|  10000| 0.1720|  0.250|    4.2430|  1.7470|
| 100000| 1.7470|  3.588|   49.3120| 18.4240|
|1000000|17.8150| 38.454|  516.3170|196.8730|

对于基准脚本,请参见 https://github.com/Dobatymo/lmdb-python-dbm/blob/master/benchmark.py

原文由 C. Yduqoli 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题