Найти - Пользователи
Полная версия: Получение больших массивов данных MySql
Начало » Базы данных » Получение больших массивов данных MySql
1
MaLS
На Windows использую Python 3.4.2 (x86) и MySql Connector 2.0.3.
import mysql.connector as connector
Мне из базы нужно получить массив интов, где то 44000 штуки.
Делаю так:
    def select_computed_series_ids(self):
        connection = None
        cursor = None
        try:
            connection = connector.connect(
                host=self.__host, database=self.__database, password=self.__password, user=self.__user)
            cursor = connection.cursor()
            cursor.execute("""
SELECT series_id
    FROM series AS
    WHERE status <> 'X'
-- LIMIT 5
""")
            return {item[0] for item in cursor}
        finally:
            if cursor:
                cursor.close()
            if connection:
                connection.close()
Если сделать ограничение (например в 1000 записей), то всё работает. Но когда ограничение снимаю, т.е. нужно получить >44000 то курсор повисает и не возвращает значение.
Пока решил проблему так:
    def select_computed_series_ids(self):
        connection = None
        cursor = None
        try:
            connection = connector.connect(
                host=self.__host, database=self.__database, password=self.__password, user=self.__user)
            cursor = connection.cursor(prepared=True)
            query = """
SELECT series_id
    FROM series 
    WHERE series_id > %s
      AND status <> 'X'
    ORDER BY series_id
LIMIT 1000
"""
            last_series_id = 0
            ids = []
            while True:
                cursor.execute(query, (last_series_id,))
                row = cursor.fetchone()
                if row is None:
                    break
                while row is not None:
                    last_series_id = row[0]
                    ids.append(last_series_id)
                    row = cursor.fetchone()
            
            return set(ids)
        finally:
            if cursor:
                cursor.close()
            if connection:
                connection.close()
Далее думаю весь функционал перевести на итераторы.
Но остаётся вопрос, как избежать зависание программы на работе курсора, т.е. правильно ли у меня делается выборка данных и какой максимум записей курсор может выдать?
py.user.next
MaLS
return {item[0] for item in cursor}
return (item[0] for item in cursor)

MaLS
На Windows использую Python 3.4.2 (x86) и MySql Connector 2.0.3.
Недавно понадобилась MySQL, поставил pymysql. Он довольно удобный.

>>> import pymysql
>>> 
>>> con = pymysql.connect(host='localhost', user='guest')
>>> cur = con.cursor()
>>> cur.execute('use test')
0
>>> cur.execute('show tables')
2
>>> list(cur)
[('p',), ('t',)]
>>> con.close()
>>>

MaLS
Мне из базы нужно получить массив интов, где то 44000 штуки.

Вот открой консоль просто и вручную подключись к базе данных. Посмотри, сколько времени они выбираются. Потом - сколько времени они читаются.
MaLS
py.user.next
Вот открой консоль просто и вручную подключись к базе данных. Посмотри, сколько времени они выбираются. Потом - сколько времени они читаются.
Во втором варианте читаются быстро, так что проблема не в MySql сервере.
py.user.next
Недавно понадобилась MySQL, поставил pymysql.
Работать с большими массивами данных пробовал?
py.user.next
MaLS
Работать с большими массивами данных пробовал?

Ну, не большие, но записи по 16 текстовых полей за две секунды читает.
>>> import pymysql
>>> 
>>> con = pymysql.connect(host='localhost', user='guest', db='test', charset='utf8')
>>> cur = con.cursor()
>>> cur.execute('select * from cond')
17184
>>>

MaLS
Во втором варианте читаются быстро, так что проблема не в MySql сервере.
Это не для проверки сервера, а для проверки модуля MySql Connector 2.0.3.
А в первом варианте что проиходит, когда вручную подключаешься?
MaLS
py.user.next
А в первом варианте что проиходит, когда вручную подключаешься?
Хорошая идея.

Вывод консоли:
Python 3.4.2 (v3.4.2:ab2c023a9432, Oct  6 2014, 22:15:05) [MSC v.1600 32 bit (Intel)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> import mysql.connector as connector
>>> connection = connector.connect(host="*****", database="*****", password="*****", user="*****")
>>> cursor = connection.cursor()
>>> cursor.execute("SELECT series_id FROM series WHERE status <> 'X'")
>>> rows = {r[0] for r in cursor}
Traceback (most recent call last):
  File "<pyshell#4>", line 1, in <module>
    rows = {r[0] for r in cursor}
  File "<pyshell#4>", line 1, in <setcomp>
    rows = {r[0] for r in cursor}
  File "C:\Program Files (x86)\Python\lib\site-packages\mysql\connector\cursor.py", line 809, in fetchone
    row, self.description)
  File "C:\Program Files (x86)\Python\lib\site-packages\mysql\connector\conversion.py", line 394, in row_to_python
    result[i] = self._cache_field_types[field_type](row[i], field)
  File "C:\Program Files (x86)\Python\lib\site-packages\mysql\connector\conversion.py", line 421, in _INT_to_python
    return int(value)
ValueError: invalid literal for int() with base 10: b'8783402\n\x00\x00\x00'
>>> 
Соответственно, если ставим ограничение, то всё работает:
Python 3.4.2 (v3.4.2:ab2c023a9432, Oct  6 2014, 22:15:05) [MSC v.1600 32 bit (Intel)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> import mysql.connector as connector
>>> connection = connector.connect(host="*****", database="*****", password="*****", user="*****")
>>> cursor = connection.cursor()
>>> cursor.execute("SELECT series_id FROM series WHERE status <> 'X' LIMIT 1000")
>>> rows = {r[0] for r in cursor}
>>> len(rows)
1000
И все данные можно выбрать, как я уже показывал выше.
py.user.next
MaLS
ValueError: invalid literal for int() with base 10: b'8783402\n\x00\x00\x00'
Это их косяк. Ошибка в модуле. Они должны стрипать нули.

>>> int(b'1\x00', 10)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: b'1\x00'
>>> int(b'\x00', 10)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: b'\x00'
>>> int(b'1\n', 10)
1
>>> 

MaLS
Соответственно, если ставим ограничение, то всё работает:
Это не из-за количества, а просто доходит до записи, которая с нулями приходит.
sander
ставьте mysqlclient - форк MySQldb для python 3, быстрее чем pymysql
py.user.next
sander
ставьте mysqlclient - форк MySQldb
Что-то там исходники какие-то не такие. По сравнению с pymysql выглядит так, будто какой-то студент форкнул, тогда как в pymysql всё профессионально сделано.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB