在sqlite中插入大量数据
Inserting large amounts of data in sqlite
我正在为 sqlite3 中的数据库进行倒排索引查找 table。我拥有的数据库包含某些博主及其 posts.
我有一个 table post,其中包含列 id、text、blogger_id。这个 table 由 ~680 000 post 组成。我想用 blogger_id、post_id、word_position、word_id.
列创建一个 table Blogger_Post_Word
我正在为此使用 Python,我之前尝试过两种方法,但都存在问题。
我在网上看到,插入大量数据的最佳方法是使用批量插入。这意味着我必须获取所有 post,并且对于 post 中的每个单词,我必须将其存储在本地,以便稍后进行批量插入。这需要很多我没有的内存。
我也尝试过一个一个地插入每个单词,但这太长了。
是否有解决此问题的有效方法或一次性解决此问题的 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 是我写的 class 来处理数据库,这些是 class 我使用的函数:
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]) + ')'
好的,希望对大家有所帮助。
问题确实是插入一个太慢了,我没有足够的内存来本地存储整个列表。
相反,我混合使用了两者并将它们增量地插入到数据库中。
我显示了列表的大小以确定瓶颈。 68万中的15万个帖子好像是我的瓶颈。列表的总大小约为 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
我正在为 sqlite3 中的数据库进行倒排索引查找 table。我拥有的数据库包含某些博主及其 posts.
我有一个 table post,其中包含列 id、text、blogger_id。这个 table 由 ~680 000 post 组成。我想用 blogger_id、post_id、word_position、word_id.
列创建一个 table Blogger_Post_Word我正在为此使用 Python,我之前尝试过两种方法,但都存在问题。
我在网上看到,插入大量数据的最佳方法是使用批量插入。这意味着我必须获取所有 post,并且对于 post 中的每个单词,我必须将其存储在本地,以便稍后进行批量插入。这需要很多我没有的内存。
我也尝试过一个一个地插入每个单词,但这太长了。
是否有解决此问题的有效方法或一次性解决此问题的 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 是我写的 class 来处理数据库,这些是 class 我使用的函数:
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]) + ')'
好的,希望对大家有所帮助。
问题确实是插入一个太慢了,我没有足够的内存来本地存储整个列表。
相反,我混合使用了两者并将它们增量地插入到数据库中。
我显示了列表的大小以确定瓶颈。 68万中的15万个帖子好像是我的瓶颈。列表的总大小约为 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