将 Python NumPy 数组插入 PostgreSQL 数据库的最佳方法

Dan*_*and 11 python sql postgresql numpy

我们的团队使用的软件严重依赖将 NumPy 数据转储到文件中,这大大降低了我们的代码速度。如果我们可以将 NumPy 数组直接存储在 PostgreSQL 中,我们将获得重大的性能提升。

欢迎使用其他在任何数据库或可搜索的类似数据库的结构中存储 NumPy 数组的高性能方法,但最好使用 PostgresSQL。

我的问题与之前提出的问题非常相似。但是,我正在寻找一个更强大、更高效的答案,我希望存储任何任意 NumPy 数组。

Vla*_*lad 9

不确定这是否是您所追求的,但假设您具有对现有 postgres 数据库的读/写访问权限:

import numpy as np
import psycopg2 as psy
import pickle

db_connect_kwargs = {
    'dbname': '<YOUR_DBNAME>',
    'user': '<YOUR_USRNAME>',
    'password': '<YOUR_PWD>',
    'host': '<HOST>',
    'port': '<PORT>'
}

connection = psy.connect(**db_connect_kwargs)
connection.set_session(autocommit=True)
cursor = connection.cursor()

cursor.execute(
    """
    DROP TABLE IF EXISTS numpy_arrays;
    CREATE TABLE numpy_arrays (
        uuid VARCHAR PRIMARY KEY,
        np_array_bytes BYTEA
    )
    """
)
Run Code Online (Sandbox Code Playgroud)

这种方法的要点是将任何 numpy 数组(任意形状和数据类型)存储为numpy_arrays表中的一行,其中uuid是一个唯一标识符,以便以后能够检索该数组。实际数组将np_array_bytes作为字节保存在列中。

插入数据库:

some_array = np.random.rand(1500,550)
some_array_uuid = 'some_array'

cursor.execute(
    """
    INSERT INTO numpy_arrays(uuid, np_array_bytes)
    VALUES (%s, %s)
    """,
    (some_array_uuid, pickle.dumps(some_array))
)
Run Code Online (Sandbox Code Playgroud)

从数据库查询:

uuid = 'some_array'
cursor.execute(
    """
    SELECT np_array_bytes
    FROM numpy_arrays
    WHERE uuid=%s
    """,
    (uuid,)
)
some_array = pickle.loads(cursor.fetchone()[0])
Run Code Online (Sandbox Code Playgroud)

表现?

如果我们可以将 NumPy 数组直接存储在 PostgreSQL 中,我们将获得重大的性能提升。

我没有以任何方式对这种方法进行基准测试,所以我无法确认或反驳这一点......

磁盘空间?

我的猜测是,这种方法占用的磁盘空间与使用np.save('some_array.npy', some_array). 如果这是一个问题,请考虑在插入之前压缩字节。

  • Unpickling 允许执行任意 python 代码,因此您永远不应该 unpickle 不可信的东西。如果允许不同的进程为此列保存任意值,则存在(尽管很小)可利用的安全缺陷。要关闭它,您可以使用`bf = io.BytesIO(); some_array = np.load(bf, allowed_pickle=False)` 来加载数据(与保存类似) (3认同)