Pandas: to_sql بطيء جدًا

تم إنشاؤها على ١ فبراير ٢٠١٧  ·  24تعليقات  ·  مصدر: pandas-dev/pandas

عينة التعليمات البرمجية ،

df_name.to_sql('table_name',
                          schema = 'public',
                          con = engine,
                          index = False,
                          if_exists = 'replace')

وصف المشكلة

أنا أكتب 500000 صف إطار بيانات إلى قاعدة بيانات postgres AWS ويستغرق الأمر وقتًا طويلاً جدًا لدفع البيانات من خلالها.

إنه خادم SQL كبير إلى حد ما واتصالي بالإنترنت ممتاز ، لذا فقد استبعدت أن يساهم ذلك في المشكلة.

وبالمقارنة ، فإن استخدام csv2sql أو استخدام cat والأنابيب في psql في سطر الأوامر يكون أسرع بكثير.

IO SQL Usage Question

التعليق الأكثر فائدة

أضف هذا الرمز أدناه engine = create_engine(connection_string) :

from sqlalchemy import event

@event.listens_for(e, 'before_cursor_execute')
def receive_before_cursor_execute(conn, cursor, statement, params, context, executemany):
    if executemany:
        cursor.fast_executemany = True
        cursor.commit()

في الكود الخاص بي ، كانت الوظيفة to_sql تستغرق 7 دقائق للتنفيذ ، والآن تستغرق 5 ثوانٍ فقط ؛)

ال 24 كومينتر

انظر هنا: http://stackoverflow.com/questions/33816918/write-large-pandas-dataframes-to-sql-server-database

باستخدام SQLServer ، تحتاج إلى الاستيراد عبر csv مع تحميل مجمع لتحقيق الكفاءة

قد تجد هذا مفيدًا: http://odo.pydata.org/en/latest/perf.html

لن يعمل ODO بالنسبة لي ، فهو يولد أخطاء لم أتمكن من إصلاحها ، لكن d6tstack يعمل بشكل جيد https://github.com/d6t/d6tstack/blob/master/examples-sql.ipynb. يمكنك المعالجة المسبقة مع الباندا ويستخدم postgres COPY FROM لجعل الاستيراد سريعًا. يعمل بشكل جيد مع postgres RDS.

أضف هذا الرمز أدناه engine = create_engine(connection_string) :

from sqlalchemy import event

@event.listens_for(e, 'before_cursor_execute')
def receive_before_cursor_execute(conn, cursor, statement, params, context, executemany):
    if executemany:
        cursor.fast_executemany = True
        cursor.commit()

في الكود الخاص بي ، كانت الوظيفة to_sql تستغرق 7 دقائق للتنفيذ ، والآن تستغرق 5 ثوانٍ فقط ؛)

شكراllautert!
هذا ساعد كثيرا!

# dont forget to import event
from sqlalchemy import event, create_engine

engine = create_engine(connection_string)

@event.listens_for(engine, 'before_cursor_execute')
def receive_before_cursor_execute(conn, cursor, statement, params, context, executemany):
    if executemany:
        cursor.fast_executemany = True
        cursor.commit()

لقد حاولت تشغيل هذا الإصلاح ، لكنني واجهت رسالة خطأ:

AttributeError: 'psycopg2.extensions.cursor' object has no attribute 'fast_executemany'

هل يعلم احدكم ماذا يحدث؟

مرحبًا @ tim-sauchuk ، واجهت نفس الخطأ أيضًا ، على الرغم من أنني وجدت حلاً يعمل بشكل رائع يتضمن تعديلًا بسيطًا لملف pandas.io.sql.py (فقط احذف ملف .pyc من __pycache__ قبل الاستيراد مرة أخرى للتأكد من أنه يكتب الإصدار الجديد في الملف المضغوط)

https://github.com/pandas-dev/pandas/issues/8953

مرحبًا @ tim-sauchuk ، واجهت نفس الخطأ أيضًا ، على الرغم من أنني وجدت حلاً يعمل بشكل رائع يتضمن تعديلًا بسيطًا لملف pandas.io.sql.py (فقط احذف ملف .pyc من

8953

المشكلة رقم 8953 التي ذكرها @ bsaunders23 توضح أيضًا طريقة لـ "تصحيح القرد" (إصلاحه في وقت التشغيل). لقد جربته ، واستغرقت مجموعة البيانات 20 ألفًا التي استغرقت أكثر من 10 دقائق للتحميل ثم 4 ثوانٍ فقط.

شكراllautert!
هذا ساعد كثيرا!

# dont forget to import event
from sqlalchemy import event, create_engine

engine = create_engine(connection_string)

@event.listens_for(engine, 'before_cursor_execute')
def receive_before_cursor_execute(conn, cursor, statement, params, context, executemany):
    if executemany:
        cursor.fast_executemany = True
        cursor.commit()

هل يعرف أي شخص كيف يمكنني تنفيذ هذا الحل داخل الفصل باستخدام مثيل self.engine؟

هل يعرف أي شخص كيف يمكنني تنفيذ هذا الحل داخل الفصل باستخدام مثيل self.engine؟

يعمل بالنسبة لي بالإشارة إلى self.engine

مثال:

    self.engine = sqlalchemy.create_engine(connectionString, echo=echo)
    self.connection = self.engine.connect()

    @event.listens_for(self.engine, 'before_cursor_execute')
    def receive_before_cursor_execute(conn, cursor, statement, params, context, executemany):
        print("Listen before_cursor_execute - executemany: %s" % str(executemany))
        if executemany:
            cursor.fast_executemany = True
            cursor.commit()

لا يعمل بالنسبة لي. ما هو إصدار الباندا و sqlalchemy الذي تستخدمه؟

جربته تشغيل sqlalchemy: 1.2.4-py35h14c3975_0 و 1.2.11-py35h7b6447c_0

لكني أحصل

AttributeError: الكائن 'psycopg2.extensions.cursor' ليس له سمة 'fast_executemany'

@ dean12llautert

كيف يبدو استدعاء الوظيفة في هذا السياق؟ أو بعبارة أخرى ، ما الذي تستخدمه في الوسيطات لتحميل الجدول بنجاح؟

<# dont forget to import event
from sqlalchemy import event, create_engine

engine = create_engine(connection_string)

@event.listens_for(engine, 'before_cursor_execute')
def receive_before_cursor_execute(conn, cursor, statement, params, context, executemany):
    if executemany:
        cursor.fast_executemany = True
        cursor.commit()>``

جربته تشغيل sqlalchemy: 1.2.4-py35h14c3975_0 و 1.2.11-py35h7b6447c_0

لكني أحصل

AttributeError: الكائن 'psycopg2.extensions.cursor' ليس له سمة 'fast_executemany'

أنت تستخدم psycopg2 ، وهو برنامج postgresql. تتعلق هذه المشكلة والإصلاح بـ Microsoft SQL Server باستخدام برنامج تشغيل pyodbc.

ماذا عن إضافة معلمة "dtype"

هل يعرف أي شخص كيف يمكنني تنفيذ هذا الحل داخل الفصل باستخدام مثيل self.engine؟

يعمل بالنسبة لي بالإشارة إلى self.engine

مثال:

    self.engine = sqlalchemy.create_engine(connectionString, echo=echo)
    self.connection = self.engine.connect()

    @event.listens_for(self.engine, 'before_cursor_execute')
    def receive_before_cursor_execute(conn, cursor, statement, params, context, executemany):
        print("Listen before_cursor_execute - executemany: %s" % str(executemany))
        if executemany:
            cursor.fast_executemany = True
            cursor.commit()

هل اكتشفت كيف؟

أعتقد أن الإجابة الصحيحة يجب أن تكون باستخدام https://docs.sqlalchemy.org/en/13/dialects/postgresql.html#psycopg2 -batch-mode-fast -ecution ، إذا كنت تحاول حفظ pandas dataframe إلى postgres

يحتوي إصدار جديد من الباندا على معلمة method والتي يمكن اختيارها لتكون "متعددة". هذا يجعل الكود يعمل بشكل أسرع.

fast_executemany بخطوة واحدة (sqlalchemy> = 1.3.0):

engine = sqlalchemy.create_engine(connection_string, fast_executemany=True)

ربما يجدر ذكره في مكان ما في المستندات أو مع مثال؟ إنها حالة خاصة لا تتعلق بالباندا ، لكنها إضافة صغيرة يمكن أن تحسن الأداء بشكل كبير في كثير من الحالات.

يحتوي إصدار جديد من الباندا على معلمة method والتي يمكن اختيارها لتكون "متعددة". هذا يجعل الكود يعمل بشكل أسرع.

كنت تعتقد أن تعيين المعلمة chunksize سيكون كافيًا لإدراج الدفعة to_sql ولكن لا.

البديل لمستخدمي MS SQL هو استخدام turbodbc.Cursor.insertmanycolumns ، لقد أوضحت ذلك في منشور StackOverflow المرتبط: https://stackoverflow.com/a/62671681/1689261

بالنسبة للقراء المستقبليين حول هذا الموضوع ، هناك خياران لاستخدام "batch_mode" لـ to_sql. فيما يلي مجموعتان:

create_engine(connection_string, executemany_mode='batch', executemany_batch_page_size=x)

أو

create_engine(connection_string, executemany_mode='values', executemany_values_page_size=x)

يمكن العثور على تفاصيل هذه الحجج هنا: https://docs.sqlalchemy.org/en/13/dialects/postgresql.html#psycopg2 -fast -ecution-helpers

بالنسبة لمستخدمي postgres ، أوصي بتعيين method إلى مكالمة قابلة للاستدعاء:

يمكن الاستدعاء مع التوقيع (pd_table، conn، keys، data_iter): يمكن استخدام هذا لتنفيذ طريقة إدراج أكثر كفاءة بناءً على ميزات لهجة خلفية محددة.

واستدعاء الوظيفة من مثال الكود هنا https://pandas.pydata.org/pandas-docs/stable/user_guide/io.html#insertion -method and

استخدام COPY FROM أسرع كثيرًا 🚀

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات