Почему SQLite3 выполняет запросы медленнее, чем создание нового индекса каталога с pandas - PullRequest
0 голосов
/ 03 августа 2020

У меня есть сценарий, который требует, чтобы все файлы в заданном каталоге были проиндексированы для упрощения запросов (например, найти файл с заданным именем файла, имеющим самую последнюю дату изменения). Я просматривал весь каталог и добавлял каждый файл в фрейм данных каждый раз, когда запускался скрипт. Я бы подумал, что вместо того, чтобы собирать эти данные для каждого файла, было бы быстрее запросить базу данных и обновлять только в том случае, если измененные данные файлов изменились, но при тестировании это было намного медленнее. Почему это? Есть ли более эффективный способ сделать это?

Результат:

Index with pandas took 0:06:53.352515
Innitial index with SQLite3 took 0:43:20.042651
second index with SQLite3 took 0:21:48.863566

"""
{Description}
The purpose of this exercise is to index a directory for later use.
We will try two methods to quantify the benefits of updating a SQLite db
    rather than re-indexing into a pandas dataframe each time.
"""

# Built-in/Generic Imports
import os
import sys
# […]

# Libs
import pandas as pd # Or any other
import datetime
import sqlite3

def main():
    dbPath = os.path.join(os.getcwd(), 'testing.db')
    indexPath = Random_Directory_with_tons_of_files
    setupSQL(dbPath)
    print('Index with pandas took ' + str(testPandas(indexPath)))
    print('Innitial index with SQLite3 took ' + str(testSQLite(indexPath, dbPath)))
    print('second index with SQLite3 took ' + str(testSQLite(indexPath, dbPath)))

def setupSQL(dbPath):
    if os.path.exists(dbPath):
        os.remove(dbPath)
    conn = sqlite3.connect(dbPath)
    c = conn.cursor()
    c.execute('''CREATE TABLE testTable
             (fullPath, fileName, modifiedDate)''')
    conn.commit()
    conn.close()

def testPandas(path):
    startTime = datetime.datetime.now()
    testIndex = pd.DataFrame(columns=['fullPath', 'fileName', 'modifiedDate'])
    for dirpath, dirnames, filenames in os.walk(path):
        for filename in filenames:
            testIndex = testIndex.append({'fullPath' : os.path.join(dirpath, filename),
                                          'fileName' : filename,
                                          'modifiedDate' : os.path.getmtime(os.path.join(dirpath, filename))}, ignore_index=True)
    return datetime.datetime.now() - startTime

def testSQLite(path, dbPath):
    startTime = datetime.datetime.now()
    conn = sqlite3.connect(dbPath)
    c = conn.cursor()
    
    for dirpath, dirnames, filenames in os.walk(path):
        for filename in filenames:
            c.execute('SELECT * FROM testTable WHERE fullPath=?', [(os.path.join(dirpath, filename))])
            row = c.fetchone()
            if row == None:
                #File is not in database, add it
                c.execute('INSERT INTO testTable VALUES (?,?,?)', [
                              (os.path.join(dirpath, filename)),
                              (filename),
                              (os.path.getmtime(os.path.join(dirpath, filename)))
                              ])
                conn.commit()
            elif row[2] != os.path.getmtime(os.path.join(dirpath, filename)):
                #Modified Date has changed, update it.
                c.execute('UPDATE testTable SET modifiedDate=? WHERE fullPath=?', [(os.path.getmtime(os.path.join(dirpath, filename))),(os.path.join(dirpath, filename))])
                conn.commit()
    conn.close()
    return datetime.datetime.now() - startTime

if __name__ == '__main__':
    print('Starting')
    main()
    print('Done')

1 Ответ

0 голосов
/ 03 августа 2020

Самая большая разница между sqlite и pandas заключается в том, что sqlite - это база данных на основе файла . Когда sqlite подключается к базе данных, он загружает только определенные части файла, которые содержат фактические данные. Как только вы запрашиваете у него что-то, он возвращается и читает файл, пока не находит то, что ему нужно, а затем возвращает это вам. Вот вопрос о переполнении стека, спрашивающий о sqlite и о том, как он загружает данные.

Sqlite

Одна вещь, которую вы можете попытаться увидеть, насколько быстро это ускорится, - это иметь sqlite создает базу данных inmemory. Вместо того, чтобы передавать путь к файлу для sqlite, просто передайте :MEMORY:, и это должно создать базу данных sqlite в памяти. Затем повторите тест и посмотрите, улучшится ли скорость. ПРЕДУПРЕЖДЕНИЕ в зависимости от того, сколько файлов вы захватываете, вы можете использовать для этого много памяти.

conn = sqlite3.connect(':memory:')

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...