在sqlite中插入大量数据

Posted

技术标签:

【中文标题】在sqlite中插入大量数据【英文标题】:Inserting large amounts of data in sqlite 【发布时间】:2020-05-11 13:53:50 【问题描述】:

我正在 sqlite3 中为我的数据库创建一个倒排索引查找表。我拥有的数据库由某些博主及其帖子组成。

我有一个表格帖子,其中包含 id、text、blogger_id 列。该表包含约 680 000 个帖子。我想创建一个 Blogger_Post_Word 表,其中包含 blogger_id、post_id、word_position、word_id 列。

我为此使用 Python,之前尝试过两种方法,但都有各自的问题。

我在网上看到插入大量数据的最佳方法是使用批量插入。这意味着我必须获取所有帖子,并且对于帖子中的每个单词,我必须将其存储在本地,以便稍后进行批量插入。这需要大量我没有的内存。

我也尝试过逐个插入每个单词,但这需要很长时间。

有没有一种有效的方法来解决这个问题或者一个sql语句可以一次性解决这个问题?

编辑: 这是我现在使用的代码:

@lru_cache()
def get_word_id(_word: str) -> int:
    word_w_id = db.get_one('Word', ['word'], (word,))
    if word_w_id is None:
        db.insert_one('Word', ['word'], (word,))
        word_w_id = db.get_one('Word', ['word'], (word,))
    return word_w_id[0]

for post_id, text, creation_date, blogger_id in db.get_all('Post'):
    split_text = text.split(' ')

    for word_position, word in enumerate(split_text):
        word_id = get_word_id(word)

        db.insert_one('Blogger_Post_Word',
                      ['blogger_id', 'post_id', 'word_position', 'word_id'],
                      (blogger_id, post_id, word_position, word_id))

db 是我编写的用于处理数据库的类,这些是我使用的类中的函数:

def get(self, table: str, where_cols: list = None, where_vals: tuple = None):
    query = 'SELECT * FROM ' + table

    if where_cols is not None and where_vals is not None:
        where_cols = [w + '=?' for w in where_cols]
        query += ' WHERE ' + ' and '.join(where_cols)

        return self.c.execute(query, where_vals)

    return self.c.execute(query)

def get_one(self, table: str, where_cols: list = None, where_vals: tuple = None):
    self.get(table, where_cols, where_vals)
    return self.c.fetchone()



def insert_one(self, table: str, columns: list, values: tuple):
    query = self.to_insert_query(table, columns)
    self.c.execute(query, values)
    self.conn.commit()


def to_insert_query(self, table: str, columns: list):
    return 'INSERT INTO ' + table + '(' + ','.join(columns) + ')' + ' VALUES (' + ','.join(['?' for i in columns]) + ')'

【问题讨论】:

欢迎来到 SO!你试过什么了?向我们展示您的代码,我们很乐意为您提供帮助 谢谢!我编辑了我的问题并添加了我使用的代码。 您可能想查看 sqlite 的全文搜索扩展。 我正在专门研究反向查找,所以我也想自己编写代码,但谢谢! 【参考方案1】:

好的,我希望这对任何人都有帮助。

问题是插入一个确实太慢了,而且我没有足够的内存来本地存储整个列表。

相反,我使用了两者的混合,并将它们增量插入到数据库中。

我显示了列表的大小以确定瓶颈。似乎 680 000 个帖子中的 150 000 个帖子是我的瓶颈。列表的总大小约为 4.5 GB。

from pympler.asizeof import asizeof
print(asizeof(indexed_data))

>>> 4590991936

我决定增加 50 000 个帖子以保持一切顺利。

现在这是我的代码:

# get all posts
c.execute('SELECT * FROM Post')
all_posts = c.fetchall()

increment = 50000

start = 0
end = increment

while start < len(all_posts):
    indexed_data = []

    print(start, ' -> ', end)

    for post_id, text, creation_date, blogger_id in all_posts[start:end]:
        split_text = text.split(' ')

        # for each word in the post add a tuple with blogger id, post id, word position in the post and the word to indexed_data
        indexed_data.extend([(blogger_id, post_id, word_position, word) for word_position, word in enumerate(split_text)])

    print('saving...')
    c.executemany('''
    INSERT INTO Inverted_index (blogger_id, post_id, word_position, word)
    VALUES (?, ?, ?, ?)
    ''', indexed_data)

    start += increment
    if end + increment > len(all_posts):
        end = len(all_posts)
    else:
        end += increment

【讨论】:

以上是关于在sqlite中插入大量数据的主要内容,如果未能解决你的问题,请参考以下文章

Sqlite3插入大量数据性能优化

在 nsthread 上运行的 iPhone Sqlite 插入

在Android中处理非常大量数据的好方法是啥?

使用 python 在 sqlite3 数据库中存储大量 API 数据的最有效方法

VB.Net 向 SQLite-DB 写入大量数据

SQLite vs Core Data:保存大量数据