将大型 python 列表传递到 SQLite SELECT 语句时如何提高性能?

Posted

技术标签:

【中文标题】将大型 python 列表传递到 SQLite SELECT 语句时如何提高性能?【英文标题】:How can I boost performance when passing large python lists into SQLite SELECT statements? 【发布时间】:2022-01-20 12:36:22 【问题描述】:

在循环大型 python 列表中的字符串并将它们传递到 SQLite SELECT 语句以返回值时,我遇到了巨大的性能下降,每个循环需要 0.5 到 0.7 秒。 (10K 字符串约 2 小时)

在普遍搜索之后,我不确定如何实现一种方法,以便将列表“批量”导出到更少的合并查询中,以期加快速度。

我有这个从函数生成的文件名列表:

documents = ['value1.xlsx', 'value2.docx', 'value3.txt', 'value4.csv', ...]

我还有一个 1GB 的大型数据库,其中包含唯一的文件名和文件哈希。

def iterate_documents(cur, documents):
    i = 0
    output = [] # Declare Empty List
    while i < len(documents):
        # Returning the MD5 Hash of a Passed File Name
        match = cur.execute('SELECT md5hash FROM hash_table WHERE name=?', (documents[i],)).fetchone()

        # If a File Name hasn't been seen by the DB, say the hash is "Unknown"
        if match is None or len(match) == 0:
            match = "Unknown"
        else:
            match = match[0]

        output.append(match) # Append the match or 'Unknown' to the Output List
        i += 1
    return output

示例输出:hashes = [hash-1, hash-2, Unknown, value-4, ...]

接下来我要做的是使用有序输出来匹配元组(documents[i], hashes[i]) 中的文档和哈希。示例:('value1.xlsx', 'hash-1')

所以我需要iterate_documents() 值保持传递顺序。到目前为止,蛮力循环是我得到的最好的!

【问题讨论】:

【参考方案1】:

因为它只有 10k 个项目,我可能只从数据库中获取您需要的项目,然后在本地进行更多匹配:

import sqlite3

def chunks(l, n):
    for i in range(0, len(l), n):
        yield l[i:i + n]

conn = sqlite3.connect('test.db')

conn.execute('''
    CREATE TABLE IF NOT EXISTS hash_table(
        name TEXT PRIMARY KEY NOT NULL,
        md5hash TEXT
    );
''')
conn.execute("INSERT INTO hash_table(name,md5hash) VALUES ('value1.xlsx', 'some hash of value1.xlsx');")
conn.execute("INSERT INTO hash_table(name,md5hash) VALUES ('value2.docx', 'some hash of value2.docx');")

documents = ['value1.xlsx', 'value2.docx', 'value3.txt', 'value4.csv']
lookup = 

## -----------------------
## load the lookup in chunks due to limits of SQLLite
# ## -----------------------
chunck_size = 100
for chunc in chunks(documents, chunck_size):
    sql = f"SELECT name, md5hash FROM hash_table WHERE name in (','.join(['?']*len(chunc)))"
    lookup = **lookup, **dict(conn.execute(sql, chunc).fetchall())
## -----------------------

doc_with_hash = doc: lookup.get(doc, "Unknown") for doc in documents
print(doc_with_hash)

这应该给你:


    'value1.xlsx': 'some hash of value1.xlsx',
    'value2.docx': 'some hash of value2.docx',
    'value3.txt': 'Unknown',
    'value4.csv': 'Unknown'

【讨论】:

【参考方案2】:

你有几个 Python 性能的选择,而不需要做太多的代码修改。

1.) 你可以使用 PyPy

这是最简单的方法

PyPy 是一种运行时解释器,它比完全解释型语言快,但比完全编译型语言(如 C)慢。

PyPY Link

2.) 你可以尝试多线程或并行处理

这会更难

Threading Docs

通过代码修改,您也有几个选择。

1.) 使用 for 循环而不是 while 循环

for 循环在 python 中更快,但在 C 中却没有

Comparing for loops to while loops

2.) 不要将变量 documents 传递给函数 变量documents 是一个可变值,它会随着变大而变化。 这会导致函数出现问题,因为您每次都在重新创建 var

【讨论】:

以上是关于将大型 python 列表传递到 SQLite SELECT 语句时如何提高性能?的主要内容,如果未能解决你的问题,请参考以下文章

如何将大型 JSON 数据从服务器存储到 SQLITE Android?

如何通过单击按钮将 Listview 中的数据传递到购物车列表(新活动)。我插入到 listview 的数据正在使用 SQLite

如何将数据从 sqlite 数据库传递到另一个活动?

Python 帮助延迟加载大型数据集

将列表框的选定项传递到 xaml

将大型数组缓存到 SQLite - Java/Android