Ситуация
Я использую Python 3.7.2 со встроенным модулем sqlite3.(sqlite3.version == 2.6.0)
У меня есть база данных sqlite, которая выглядит следующим образом:
| user_id | action | timestamp |
| ------- | ------ | ---------- |
| Alice | 0 | 1551683796 |
| Alice | 23 | 1551683797 |
| James | 1 | 1551683798 |
| ....... | ...... | .......... |
, где user_id
равно TEXT
, action
является произвольным INTEGER
, а timestamp
- это INTEGER
, представляющее время UNIX.
База данных имеет 200M строк, и существует 70K различных user_id
с.
Цель
Мне нужно создать словарь Python, который будет выглядеть следующим образом:
{
"Alice":[(0, 1551683796), (23, 1551683797)],
"James":[(1, 1551683798)],
...
}
, который имеет user_id
s в качестве ключей и соответствующие журналы событий в качестве значений, которые являются списками кортежей (action, timestamp)
.Надеемся, что каждый список будет отсортирован по timestamp
в порядке возрастания, но даже если это не так, я думаю, что этого легко добиться, отсортировав каждый список после создания словаря.
Усилие
У меня есть следующий код для запроса базы данных.Сначала он запрашивает список пользователей (с user_list_cursor
), а затем запрашивает все строки, принадлежащие пользователю.
import sqlite3
connection = sqlite3.connect("database.db")
user_list_cursor = connection.cursor()
user_list_cursor.execute("SELECT DISTINCT user_id FROM EVENT_LOG")
user_id = user_list_cursor.fetchone()
classified_log = {}
log_cursor = connection.cursor()
while user_id:
user_id = user_id[0] # cursor.fetchone() returns a tuple
query = (
"SELECT action, timestamp"
" FROM TABLE"
" WHERE user_id = ?"
" ORDER BY timestamp ASC"
)
parameters = (user_id,)
local_cursor.execute(query, parameters) # Here is the bottleneck
classified_log[user_id] = list()
for row in local_cursor.fetchall():
classified_log[user_id].append(row)
user_id = user_list_cursor.fetchone()
Проблема
Выполнение запроса для каждого пользователя слишкоммедленный.Эта единственная строка кода (которая комментируется как бутылочное горлышко ) занимает около 10 секунд для каждого user_id
.Я думаю, что я делаю неправильный подход с запросами.Как правильно достичь цели?
Я попытался выполнить поиск по ключевым словам «классифицировать БД по столбцу», «классифицировать БД по столбцу», «Журнал SQL в словарь Python», но, похоже, ничего не соответствуетмоя ситуация.Я думаю, что это не будет редкой необходимостью, поэтому, возможно, мне не хватает подходящего ключевого слова для поиска.
Воспроизводимость
Если кто-то желает воспроизвести ситуацию с 200M строкой sqliteбазы данных, следующий код создаст файл базы данных объемом 5 ГБ.
Но я надеюсь, что есть кто-то, кто знаком с такой ситуацией и знает, как написать правильный запрос.
import sqlite3
import random
connection = sqlite3.connect("tmp.db")
cursor = connection.cursor()
cursor.execute(
"CREATE TABLE IF NOT EXISTS EVENT_LOG (user_id TEXT, action INTEGER, timestamp INTEGER)"
)
query = "INSERT INTO EVENT_LOG VALUES (?, ?, ?)"
parameters = []
for timestamp in range(200_000_000):
user_id = f"user{random.randint(0, 70000)}"
action = random.randint(0, 1_000_000)
parameters.append((user_id, action, timestamp))
cursor.executemany(query, parameters)
connection.commit()
cursor.close()
connection.close()