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

sqlite3: Connect to a database in cloud (S3)

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

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

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

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

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

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

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

SQLite有一个OS Interface or VFS. Using a Python SQLite wrapper called APSW的概念,你可以为任意文件系统编写一个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 实施(S3 连接需要 APSW 库和 boto3)

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)

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

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

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

是的,使用 EFS 是可能的:

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

AWS 最近发布了 AWS Lambda 和 Amazon EFS 之间的集成。 它支持 SQLite 所需的 NFSv4 锁 upgrading/downgrading。 这意味着 SQLite 引擎可以 read/write 访问存储在 EFS 文件系统上的文件。

(灵感来自

如果数据库只是用于读取,则有https://github.com/michalc/sqlite-s3-query(完全公开:由我编写)

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

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)