【问题标题】:SQLite Database: One Big vs. Several Small? Write to Database in Parallel?SQLite 数据库:一个大对几个小?并行写入数据库?
【发布时间】:2020-02-25 00:43:11
【问题描述】:

由于我是 sqlite 数据库的新手,我非常感谢每一个有用的评论、答案或对有趣线程和网站的引用。这是我的情况:

我有一个包含 400 个 txt 文件的目录,每个文件的大小约为 7GB。这些文件中的相关信息被写入一个 sqlite 数据库,生成一个 17.000.000x4 的表,大约需要 1 天。稍后将仅由我查询数据库以进一步分析数据。

如果可以并行写入数据库,则可以显着加快创建数据库的整个过程。例如,我可以并行运行多个进程,每个进程仅将 400 个 txt 文件中的一个作为输入并将结果写入数据库。那么是否可以让多个进程并行写入数据库?


EDIT1: 回答 w.r.t. W4t3randWinds 评论:可以(并且更快)每个核心处理 1 个文件,将结果写入数据库并在此之后合并所有数据库。但是,使用多线程写入 1 个数据库是不可能的。


此外,我想知道创建多个数据库而不是一个大数据库是否更有效?例如,为每个 txt 文件创建一个数据库是否有意义,从而导致 400 个数据库由一个 17.000.000/400 x 4 表组成?

最后,我将数据库作为文件存储在我的机器上。但是,我还阅读了有关设置服务器的可能性。那么什么时候使用服务器有意义,更具体地说,在我的情况下使用服务器是否有意义?

请看下面我创建数据库的代码。

### SET UP
# set up database
db = sqlite3.connect("mydatabase.db")
cur = db.cursor()
cur.execute("CREATE TABLE t (sentence, ngram, word, probability);")
# set up variable to store db rows
to_db = []
# set input directory
indir = '~/data/'

### PARSE FILES
# loop through filenames in indir
for filename in os.listdir(indir):
    if filename.endswith(".txt"):
        filename = os.path.join(indir, filename)
        # open txt files in dir
        with io.open(filename, mode = 'r', encoding = 'utf-8') as mytxt:

            ### EXTRACT RELEVANT INFORMATION
            # for every line in txt file
            for i, line in enumerate(mytxt): 
                # strip linebreak
                line = line.strip()
                # read line where the sentence is stated
                if i == 0 or i % 9 == 0:
                    sentence = line
                    ngram = " ".join(line.split(" ")[:-1])
                    word = line.split(" ")[-1]
                # read line where the result is stated
                if (i-4) == 0 or (i-4) % 9 == 0:
                    result = line.split(r'=  ')[1].split(r' [')[0]
                    # make a tuple representing a new row of db
                    db_row = (sentence, ngram, word, result)
                    to_db.append(db_row)

            ### WRITE TO DATABASE               
            # add new row to db
            cur.executemany("INSERT INTO t (sentence, ngram, word, results) VALUES (?, ?, ?, ?);", to_db)
            db.commit()
db.close() 

【问题讨论】:

  • 通过将一个文件并行写入数据库(例如 4cores - 1 个文件)是不可能实现显着加速的。但是,您可以使用像 GNU 并行这样的工具来并行处理文件,以便轻松进行多处理,但是您受限于 sqlite 是单线程的。您已经将插入分组为块,这有望帮助您解决 n+1 问题。
  • 也许我的解释不清楚。我想并行处理 x 个内核上的 x 个文件并将结果写入 x 个数据库。之后,我会将数据库合并到一个数据库中。我想知道是否可以让 x 个进程立即写入一个数据库。
  • 好的,所以合并场景是有意义的。 x 个文件上的 x 个进程满足我建议的 GNU 并行的 1 对 1 核心到数据库的要求,你的最后一个问题 x 个进程/每个数据库的文件将面临我提到的限制,因为 sqlite 是单线程的。

标签: python sqlite


【解决方案1】:

如果可以并行写入数据库,则可以显着加快创建数据库的整个过程

我不确定。你只有很少的处理,所以整个过程很可能是 io 绑定的。 SQLite 是一个非常好的工具,但它只支持一个线程写入。

可能的改进:

  • 使用 x 个线程读取和处理文本文件,单个线程以大块和队列的形式写入数据库。由于进程是 IO 绑定的,因此 Python 全局进程间锁应该不是问题
  • 在单独的计算机上使用 PostgreSQL 或 MariaDB 等全功能数据库,并在客户端计算机上使用多个进程,每个进程都处理自己的一组输入文件

无论哪种情况,我都不确定它的好处...

【讨论】:

    【解决方案2】:

    我每天使用 python 多线程更新 SQLite 数据库。它工作得很好。两个不同的表有近 20,000,000 条记录,一个有 8 个字段,另一个有 10 个。这是在我 4 岁的笔记本电脑上。

    如果您遇到性能问题,我建议您查看表的构造方式(正确的主键和索引)以及您的设备。如果您仍在使用 HDD,您将通过升级到 SSD 获得惊人的性能。

    【讨论】:

    • 我将数据库设置为cur.execute("CREATE TABLE t (sentence TEXT PRIMARY KEY, ngram TEXT, word TEXT, result FLOAT);") 行看起来像('this is an example'、'this is an'、'example'、'577')。我读到使用文本作为主键效率不高,但在我的键中它似乎最方便
    • 如果在每条记录中,句子 == ngram & word,那么您可以完全删除句子列并使用 ngram 和 word 的主键。如果不需要,不要存储重复的数据。您还应该在查询的列上设置索引。例如,如果您查询 WHERE word = ‘example’,则在 word 上创建索引。
    • 每个 ngram 和每个单词出现多次。但是,ngram 和 word 的每个组合都是唯一的。这就是为什么我将句子作为主键。我总是在 WHERE ngram == 'a ngram' & word == 'word' 上查询所以我应该为 ngram 和 word 设置索引吗?
    • 另外,我在两个表中的 PK 是两个字段的组合:ticker TEXT 和 Date DATE。同样,我的数据库非常高效。
    • 是的,我理解,我并没有对此提出质疑。我会做一个组合PK。我只是想知道指数
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多