Быстрое выполнение тысяч запросов SELECT - PullRequest
0 голосов
/ 27 февраля 2019

Ситуация

  • Работа с Python 3.7.2
  • Я прочитал превалирование таблицы MariaDB с 5М строк на сервере.
  • У меня есть локальныйтекстовый файл с 7K целыми числами, по одному в строке.
  • Целые числа представляют IDX таблицы.
  • Столбец IDX таблицы является первичным ключом.(поэтому я предполагаю, что он автоматически индексируется?)

Задача

Мне нужно выбрать все строки, IDX которых находится в текстовом файле.

Мои усилия

Версия 1

Сделайте 7K запросов, по одному для каждой строки в текстовом файле.Это делает приблизительно 130 запросов в секунду, а выполнение занимает около 1 минуты.

import pymysql
connection = pymysql.connect(....)
with connection.cursor() as cursor:
    query = (
        "SELECT *"
        " FROM TABLE1"
        " WHERE IDX = %(idx)s;"
    )

    all_selected = {}
    with open("idx_list.txt", "r") as f:
        for idx in f:
            idx = idx.strip()
            if idx:
                idx = int(idx)
                parameters = {"idx": idx}
                cursor.execute(query, parameters)
                result = cursor.fetchall()[0]
                all_selected[idx] = result

Версия 2

Выберите всю таблицу, выполните итерации курсора и строки выбора вишни.Цикл for .fetchall_unbuffered() охватывает 30-40 тыс. Строк в секунду, а весь сценарий занимает около 3 минут.

import pymysql
connection = pymysql.connect(....)
with connection.cursor() as cursor:
    query = "SELECT * FROM TABLE1"

    set_of_idx = set()
    with open("idx_list.txt", "r") as f:
        for line in f:
            if line.strip():
                line = int(line.strip())
                set_of_idx.add(line)


    all_selected = {}
    cursor.execute(query)
    for row in cursor.fetchall_unbuffered():
        if row[0] in set_of_idx:
            all_selected[row[0]] = row[1:]

Ожидаемое поведение

Мне нужно выбрать быстрее,потому что в будущем число IDX в текстовом файле вырастет до 10K-100K.

Я консультировался с другими ответами, включая this , но не могу его использовать, посколькуЯ только прочитал previlege, поэтому невозможно создать другую таблицу для объединения.

Так как я могу сделать выбор быстрее?

Ответы [ 2 ]

0 голосов
/ 28 февраля 2019

Благодаря подсказке (или более чем подсказка ) от @danblack я смог достичь желаемого результата с помощью следующего запроса.

query = (
    "SELECT *"
    " FROM TABLE1"
    " INNER JOIN R"
    " ON R.IDX = TABLE1.IDX;"
)
cursor.execute(query)

danblack's SELECTОператор не работал для меня, выдавая ошибку:

pymysql.err.ProgrammingError: (1064, "У вас ошибка в синтаксисе SQL; проверьте руководство, соответствующее версии вашего сервера MariaDBправильный синтаксис для использования рядом с 'IDX' в строке 1 ")

Возможно, это связано с синтаксисом соединения MariaDB, поэтому я ознакомился с документацией MariaDB по объединению таблиц .

И теперь он выбирает 7K строк за 0,9 секунды.

Оставляя здесь в качестве ответа только для полноты картины и для будущих читателей.

0 голосов
/ 27 февраля 2019

Реализация временной таблицы будет выглядеть так:

connection = pymysql.connect(....,local_infile=True)
with connection.cursor() as cursor:
    cursor.execute("CREATE TEMPORARY TABLE R (IDX INT PRIMARY KEY)")
    cursor.execute("LOAD DATA LOCAL INFILE 'idx_list.txt' INTO R")
    cursor.execute("SELECT TABLE1.* FROM TABLE1 JOIN R USING IDX")
    ..
    cursor.execute("DROP TEMPORARY TABLE R")
...