sqlite3:连接到云中的数据库(S3)

Posted

技术标签:

【中文标题】sqlite3:连接到云中的数据库(S3)【英文标题】:sqlite3: Connect to a database in cloud (S3) 【发布时间】:2019-11-08 15:29:35 【问题描述】:

我在 s3 存储桶中有一个小的 sqlite 数据库(110kb)。每次运行 python 应用程序时,我都想连接到该数据库。

一个选项是每次我运行 python 应用程序时下载数据库并像往常一样连接它。 但是我想知道是否存在使用S3FileSystemopen 通过内存连接到该sqlite 数据库的方法。我正在使用sqlite3 库和 python 3.6

【问题讨论】:

相关:***.com/questions/3833162/… 【参考方案1】:

正如其他答案所示,您可能不想将 SQLite 用作云中的主数据库。

但是,作为一个有趣的项目的一部分,我编写了一个 Amazon Athena 数据源连接器,允许您查询 SQLite databases in S3 from Athena。为此,我为 S3 编写了一个只读 SQLite 接口。

SQLite 有一个OS Interface or VFS 的概念。使用名为 APSW 的 Python SQLite 包装器,您可以为任意文件系统编写 VFS 实现。这就是我在我的项目中所做的,我在下面包含了实现。

为了使用它,你首先要注册 VFS,然后用这个实现创建一个新的 SQLite 连接作为驱动程序。

我应该注意到这根本没有优化,因此可能仍需要根据您的查询从 S3 读取完整的数据库。但在这种特定情况下听起来不是问题。

S3FS = S3VFS()  # S3VFS defined below

# This odd format is used due to SQLite requirements
sqlite_uri = "file://.sqlite?bucket=&immutable=1".format(
  S3_PREFIX,
  DATABASE_NAME,
  S3_BUCKET
)

connection = apsw.Connection(sqlite_uri,
  flags=apsw.SQLITE_OPEN_READONLY | apsw.SQLITE_OPEN_URI,
  vfs=S3FS.vfsname
)
cursor = connection.cursor()

一旦有了游标,就可以像这样执行标准 SQL 语句:

for x,y,z in cursor.execute("select x,y,z from foo"):
    print (cursor.getdescription())  # shows column names and declared types
    print (x,y,z)

VFS 实现(需要 APSW 库和 boto3 以实现 S3 连接)

import apsw
import sys
import boto3

VFS_S3_CLIENT = boto3.client('s3')


class S3VFS(apsw.VFS):
    def __init__(self, vfsname="s3", basevfs=""):
        self.vfsname=vfsname
        self.basevfs=basevfs
        apsw.VFS.__init__(self, self.vfsname, self.basevfs)

    def xOpen(self, name, flags):
        return S3VFSFile(self.basevfs, name, flags)


class S3VFSFile():
    def __init__(self, inheritfromvfsname, filename, flags):
        self.bucket = filename.uri_parameter("bucket")
        self.key = filename.filename().lstrip("/")
        print("Initiated S3 VFS for file: ".format(self._get_s3_url()))

    def xRead(self, amount, offset):
        response = VFS_S3_CLIENT.get_object(Bucket=self.bucket, Key=self.key, Range='bytes=-'.format(offset, offset + amount))
        response_data = response['Body'].read()
        return response_data

    def xFileSize(self):
        client = boto3.client('s3')
        response = client.head_object( Bucket=self.bucket, Key=self.key)
        return response['ContentLength']

    def xClose(self):
        pass

    def xFileControl(self, op, ptr):
        return False

    def _get_s3_url(self):
        return "s3:///".format(self.bucket, self.key)

【讨论】:

【参考方案2】:

不,不能直接连接到存储在云中的 sqlite 数据库。即使您想将数据库托管在内存中,也必须在加载到内存之前将其完全下载。要做到这一点,仍然需要首先从基于磁盘的文件中加载数据库,或者使用 DDL 命令直接在内存中创建它。据我所知,没有办法将数据流加载为 sqlite 内存数据库(请参阅Example 1: Loading and Saving In-Memory Databases)。

在这种情况下,一旦数据库断开连接,就需要重新上传到云存储。 S3FileSystem.open 只是返回一个数据流。流将允许您做的就是将文件下载到本地存储,以便可以在本地打开/操作它。

如果您真的需要云数据库,则需要研究另一种托管数据库。

【讨论】:

这里是another answer,可以更深入地了解 sqlite 的用途。【参考方案3】:

是的,EFS 可以:

https://www.lambrospetrou.com/articles/aws-lambda-and-sqlite-over-efs/

AWS 最近发布了 AWS Lambda 和 Amazon EFS 之间的集成。 它支持 SQLite 所需的 NFSv4 锁升级/降级。 这意味着 SQLite 引擎可以对存储在 EFS 文件系统上的文件进行读/写访问。

【讨论】:

【参考方案4】:

如果您的所有操作都仅限于从 SQLite 读取,我想这是可能的。但我不知道是否也可以写作。 就我而言,我使用的是 gdal(需要 libgdal),而 gdal 的 /vsis3、/vsis3-streaming(基于 /vsicurl)使您能够从云中读取 SQLite 和许多其他数据源。如果你想使用原始 SQLite 而不是基于 gdal 的数据源层,你可以通过 gdal 的 API 将它们写入本地数据库,但是,如果是这样,为什么不直接下载并阅读它呢?

对我来说,由于我正在处理空间数据,并且 gdal 的 DataSource 提供了很多 API 来操作空间数据,因此这种方法可以正常工作。我仍在寻找一种写入基于云的 SQLite 的好方法。

仅供参考,这是gdal虚拟文件系统的文档 https://gdal.org/user/virtual_file_systems.html

【讨论】:

您可以在 S3 上执行对象锁,以实现对 SQLite 文件的一致写入操作。添加一个异步 API,它可以使用最终一致性模型在其前面排队写入,这似乎是一个可行的系统。【参考方案5】:

(灵感来自dacort's answer)

如果数据库仅用于读取,则有https://github.com/michalc/sqlite-s3-query(完全披露:由我撰写)

修改自述文件中的示例,假设您在 eu-west-2 中的存储桶中有 my-db.sqlite my-bucket(以及环境变量中的凭据):

from sqlite_s3_query import sqlite_s3_query

with \
        sqlite_s3_query(url='https://my-bucket.s3.eu-west-2.amazonaws.com/my-db.sqlite') as query, \
        query('SELECT * FROM my_table WHERE my_column = ?', params=('my-value',)) as (columns, rows):

    for row in rows:
        print(row)

【讨论】:

以上是关于sqlite3:连接到云中的数据库(S3)的主要内容,如果未能解决你的问题,请参考以下文章

python sqlite3 怎么处理

使用 JDBC 连接到托管在云中的 MongoDB 时出错

python连接sqlite3

如何将python连接到sqlite3并一次填充多行

django 模型创建连接到 mssql

如何连接到 Redshift 中的私有集群?