python(八):python使用lmdb数据库

摘要:
让系统访问大量小文件的开销很大,而LMDB使用内存映射的方式访问文件,使得文件内寻址的开销非常小,使用指针运算就能实现。数据库单文件还能减少数据集复制/传输过程的开销。

一、入门代码

LMDB的全称是Lightning Memory-Mapped Database(快如闪电的内存映射数据库),它的文件结构简单,包含一个数据文件和一个锁文件:

python(八):python使用lmdb数据库第1张

LMDB文件可以同时由多个进程打开,具有极高的数据存取速度,访问简单,不需要运行单独的数据库管理进程,只要在访问数据的代码里引用LMDB库,访问时给文件路径即可。

让系统访问大量小文件的开销很大,而LMDB使用内存映射的方式访问文件,使得文件内寻址的开销非常小,使用指针运算就能实现。数据库单文件还能减少数据集复制/传输过程的开销。

在python中使用lmdb: linux中,可以使用指令‘pip install lmdb' 安装lmdb包。

1. 生成一个空的lmdb数据库文件

1
2
3
4
5
6
7
# -*- coding: utf-8 -*-
importlmdb
# 如果train文件夹下没有data.mbd或lock.mdb文件,则会生成一个空的,如果有,不会覆盖
# map_size定义最大储存容量,单位是kb,以下定义1TB容量
env =lmdb.open("./train",map_size=1099511627776)
env.close()

2. LMDB数据的添加、修改、删除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# -*- coding: utf-8 -*-
importlmdb
# map_size定义最大储存容量,单位是kb,以下定义1TB容量
env =lmdb.open("./train", map_size=1099511627776)
txn =env.begin(write=True)
# 添加数据和键值
txn.put(key ='1', value ='aaa')
txn.put(key ='2', value ='bbb')
txn.put(key ='3', value ='ccc')
# 通过键值删除数据
txn.delete(key ='1')
# 修改数据
txn.put(key ='3', value ='ddd')
# 通过commit()函数提交更改
txn.commit()
env.close()

3. 查询lmdb数据库内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# -*- coding: utf-8 -*-
importlmdb
env =lmdb.open("./train")
# 参数write设置为True才可以写入
txn =env.begin(write=True)
############################################添加、修改、删除数据
# 添加数据和键值
txn.put(key ='1', value ='aaa')
txn.put(key ='2', value ='bbb')
txn.put(key ='3', value ='ccc')
# 通过键值删除数据
txn.delete(key ='1')
# 修改数据
txn.put(key ='3', value ='ddd')
# 通过commit()函数提交更改
txn.commit()
############################################查询lmdb数据
txn =env.begin()
# get函数通过键值查询数据
printtxn.get(str(2))
# 通过cursor()遍历所有数据和键值
forkey, value intxn.cursor():
print(key, value)
############################################
env.close()

4. 读取已有.mdb文件内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# -*- coding: utf-8 -*-
importlmdb
env_db =lmdb.Environment('trainC')
# env_db = lmdb.open("./trainC")
txn =env_db.begin()
# get函数通过键值查询数据,如果要查询的键值没有对应数据,则输出None
printtxn.get(str(200))
forkey, value intxn.cursor(): #遍历
print(key, value)
env_db.close()

二、进阶

LMDB 介绍

LMDB 全称为 Lightning Memory-Mapped Database,就是非常快的内存映射型数据库,LMDB使用内存映射文件,可以提供更好的输入/输出性能,对于用于神经网络的大型数据集( 比如ImageNet),可以将其存储在 LMDB 中。

因为最开始 Caffe 就是使用的这个数据库,所以网上的大多数关于 LMDB 的教程都通过 Caffe 实现的,对于不了解 Caffe 的同学很不友好,所以本篇文章只讲解 LMDB。

LMDB属于key-value数据库,而不是关系型数据库( 比如 MySQL ),LMDB提供 key-value 存储,其中每个键值对都是我们数据集中的一个样本。LMDB的主要作用是提供数据管理,可以将各种各样的原始数据转换为统一的key-value存储。

LMDB效率高的一个关键原因是它是基于内存映射的,这意味着它返回指向键和值的内存地址的指针,而不需要像大多数其他数据库那样复制内存中的任何内容。

LMDB不仅可以用来存放训练和测试用的数据集,还可以存放神经网络提取出的特征数据。如果数据的结构很简单,就是大量的矩阵和向量,而且数据之间没有什么关联,数据内没有复杂的对象结构,那么就可以选择LMDB这个简单的数据库来存放数据。

LMDB的文件结构很简单,一个文件夹,里面是一个数据文件和一个锁文件。数据随意复制,随意传输。它的访问简单,不需要单独的数据管理进程。只要在访问代码里引用LMDB库,访问时给文件路径即可。

用LMDB数据库来存放图像数据,而不是直接读取原始图像数据的原因:

  • 数据类型多种多样,比如:二进制文件、文本文件、编码后的图像文件jpeg、png等,不可能用一套代码实现所有类型的输入数据读取,因此通过LMDB数据库,转换为统一数据格式可以简化数据读取层的实现。
  • lmdb具有极高的存取速度,大大减少了系统访问大量小文件时的磁盘IO的时间开销。LMDB将整个数据集都放在一个文件里,避免了文件系统寻址的开销,你的存储介质有多快,就能访问多快,不会因为文件多而导致时间长。LMDB使用了内存映射的方式访问文件,这使得文件内寻址的开销大幅度降低。

LMDB 的基本函数

  • env = lmdb.open():创建 lmdb 环境
  • txn = env.begin():建立事务
  • txn.put(key, value):进行插入和修改
  • txn.delete(key):进行删除
  • txn.get(key):进行查询
  • txn.cursor():进行遍历
  • txn.commit():提交更改

创建一个 lmdb 环境:

# 安装:pip install lmdb
import lmdb

env = lmdb.open(lmdb_path, map_size=1099511627776)

lmdb_path指定存放生成的lmdb数据库的文件夹路径,如果没有该文件夹则自动创建。

map_size指定创建的新数据库所需磁盘空间的最小值,1099511627776B=1T。可以在这里进行存储单位换算

会在指定路径下创建data.mdblock.mdb两个文件,一是个数据文件,一个是锁文件。

修改数据库内容:

txn = env.begin(write=True)

# insert/modify
txn.put(str(1).encode(), "Alice".encode())
txn.put(str(2).encode(), "Bob".encode())

# delete
txn.delete(str(1).encode())

txn.commit()

先创建一个事务(transaction) 对象txn,所有的操作都必须经过这个事务对象。因为我们要对数据库进行写入操作,所以将write参数置为True,默认其为False

使用.put(key, value)对数据库进行插入和修改操作,传入的参数为键值对。

值得注意的是,需要在键值字符串后加.encode()改变其编码格式,将str转换为bytes格式,否则会报该错误:TypeError: Won't implicitly convert Unicode to bytes; use .encode()。在后面使用.decode()对其进行解码得到原数据。

使用.delete(key)删除指定键值对。

对LMDB的读写操作在事务中执行,需要使用commit方法提交待处理的事务。

查询数据库内容:

txn = env.begin()

print(txn.get(str(2).encode()))

for key, value in txn.cursor():
    print(key, value)

env.close()

每次commit()之后都要用env.begin()更新 txn(得到最新的lmdb数据库)。

使用.get(key)查询数据库中的单条记录。

使用.cursor()遍历数据库中的所有记录,其返回一个可迭代对象,相当于关系数据库中的游标,每读取一次,游标下移一位。

也可以想文件一样使用with语法:

with env.begin() as txn:
    print(txn.get(str(2).encode()))

    for key, value in txn.cursor():
        print(key, value)

完整的demo如下:

import lmdb
import os, sys

def initialize():
    env = lmdb.open("lmdb_dir")
    return env

def insert(env, sid, name):
    txn = env.begin(write=True)
    txn.put(str(sid).encode(), name.encode())
    txn.commit()

def delete(env, sid):
    txn = env.begin(write=True)
    txn.delete(str(sid).encode())
    txn.commit()

def update(env, sid, name):
    txn = env.begin(write=True)
    txn.put(str(sid).encode(), name.encode())
    txn.commit()

def search(env, sid):
    txn = env.begin()
    name = txn.get(str(sid).encode())
    return name

def display(env):
    txn = env.begin()
    cur = txn.cursor()
    for key, value in cur:
        print(key, value)


env = initialize()

print("Insert 3 records.")
insert(env, 1, "Alice")
insert(env, 2, "Bob")
insert(env, 3, "Peter")
display(env)

print("Delete the record where sid = 1.")
delete(env, 1)
display(env)

print("Update the record where sid = 3.")
update(env

免责声明:内容来源于网络,仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇CSS设置滚动条样式SQLite Expert安装与注册下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

django 数据库迁移

一,简单的数据导出与导入(简单的迁移) 1. django 项目提供了一个导出的方法 python manage.py dumpdata, 不指定 appname 时默认为导出所有的app 1 python manage.py dumpdata [appname] > appname_data.json 比如我们有一个项目叫 mysite, 里...

py2exe使用总结

假如你用python写了个小程序,想给别人用或者给别人演示,但他电脑里没装python、wxpython等,这时候你可以试试py2exe,它是一个将python脚本转换成windows上的可执行程序(*.exe)的工具。安装就不多说了,简单介绍一下使用方法 一般来说,使用py2exe的步骤如下 1. 写一个用于发布程序的设置脚本 如果你有一个名为hello...

inno setup读取注册表遇到的一个坑

一、背景       目前,公司针对PR开发的一个插件需要发布到64位系统上。该插件包括一个prm格式的文件和若干个DLL文件。其中,prm文件需要复制到PR公共插件目录下,DLL需要复制到Windows系统目录中去,这样插件才能正常的工作。公司现在要求发布插件时制作一个安装包,让用户点击安装包后自动将插件相关文件拷贝到相应目录去。本来用inno setu...

python数组操作

python中的数组其实就是list,但它更像是java的arraylist,而且功能比arraylist更强大。因为python的list其实是个对象,所以对于他的操作和删除比较有讲究。 创建列表sample_list = ['a',1,('a','b')]Python 列表操作sample_list = ['a','b',0,1,3]得到列表中的某一个...

python学习笔记-Pycharm远程连接服务器的Python虚拟环境(Virtualenv)

Virtualenv可以作为一个独立的Python虚拟环境工具,并能够建立多个相互独立,互不影响的Python工作环境。 主要解决在运行多个项目时,由于它们对应的运行环境需求不同,可能会导致项目无法正常运行的问题。 服务器设置内容: 安装Virtualenv命令: pip install virtualenv 给自己的项目创建python虚拟环境: vi...

【测试平台学习2】 Django 的初使用

前言 最近打算使用Django+Vue 打造一个简单的测试平台,本文对django 的使用略做记录 Django的安装与背景 Python 的后端主要有Django 和flask , 我对此只有粗浅的理解和认识, 使用flask 编写过一个接口Mock系统, flask是轻量化的,能快速实现接口的开发工作,但是它没有自带数据库。 Django 相对比较全面...