Psycopg2 ، postgresql ، python: أسرع طريقة إلى الإلغاء بالجملة

StackOverflow https://stackoverflow.com/questions/2271787

  •  20-09-2019
  •  | 
  •  

سؤال

أنا أبحث عن الطريقة الأكثر فاعلية لإلغاء بعض الملايين من tuples في قاعدة بيانات. أنا أستخدم Python و PostgreSQL و PSYCOPG2.

لقد أنشأت قائمة طويلة من tulpes يجب إدراجها في قاعدة البيانات ، وأحيانًا مع المعدلات مثل الهندسة Simplify.

الطريقة الساذجة للقيام بذلك ستكون تنسيق قائمة على قائمة INSERT البيانات ، ولكن هناك ثلاث طرق أخرى قرأتها:

  1. استخدام pyformat نمط الربط للإدراج حدودي
  2. استخدام executemany في قائمة tuples ، و
  3. باستخدام كتابة النتائج إلى ملف واستخدام COPY.

يبدو أن الطريقة الأولى هي الأكثر كفاءة ، لكنني أقدر رؤى قواعد الرؤى والرمز تخبرني بكيفية القيام بذلك بشكل صحيح.

هل كانت مفيدة؟

المحلول

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

نصائح أخرى

هناك جديد دليل PSYCOPG2 تحتوي على أمثلة لجميع الخيارات.

ال ينسخ الخيار هو الأكثر كفاءة. ثم التنفيذي. ثم التنفيذ مع Pyformat.

في تجربتي executemany ليس أسرع من تشغيل العديد من الإدراج بنفسك ، فإن أسرع طريقة هي تنسيق واحد INSERT مع العديد من القيم بنفسك ، ربما في المستقبل executemany سوف تتحسن ولكن في الوقت الحالي هو بطيء جدا

أنا فئة فرعية أ list والتحميل الزائد طريقة إلحاق ، لذلك عندما تصل القائمة إلى حجم معين ، أقوم بتنسيق الإدراج لتشغيله

يمكنك استخدام مكتبة تراجع جديدة:

$ pip install upsert

(قد تضطر إلى pip install decorator أول)

conn = psycopg2.connect('dbname=mydatabase')
cur = conn.cursor()
upsert = Upsert(cur, 'mytable')
for (selector, setter) in myrecords:
    upsert.row(selector, setter)

أين selector هو dict كائن مثل {'name': 'Chris Smith'} و setter هو dict مثل { 'age': 28, 'state': 'WI' }

إنه تقريبيا بالسرعة التي يتم بها كتابة رمز إدراج مخصص [/تحديث] وتشغيله مباشرة مع psycopg2... ولن ينفجر إذا كان الصف موجود بالفعل.

يمكن لأي شخص يستخدم SQLAlchemy تجربة إصدار 1.2 والذي أضاف دعمًا من إدراج السائبة لاستخدام psycopg2.extras.execute_batch () بدلاً من executemany عند تهيئة محركك باستخدام use_batch_mode = صحيح مثل:

engine = create_engine(
    "postgresql+psycopg2://scott:tiger@host/dbname",
    use_batch_mode=True)

http://docs.sqlalchem.org/en/latest/changelog/migration_12.html#change-4109

بعد ذلك ، يتعين على شخص ما استخدام SQLALCHMEY لن يكلف نفسه عناء تجربة مجموعات مختلفة من SQLA و PSYCOPG2 و SQL المباشر معًا.

الأول والثاني سيتم استخدامه معًا ، وليس بشكل منفصل. والثالث سيكون أكثر الخادم كفاءة ، لأن الخادم سيفعل الكل العمل الشاق.

بعد بعض الاختبارات ، unnest غالبًا ما يبدو أنه خيار سريع للغاية ، كما تعلمت من Clodoaldo Netoإجابه لسؤال مماثل.

data = [(1, 100), (2, 200), ...]  # list of tuples

cur.execute("""CREATE TABLE table1 AS
               SELECT u.id, u.var1
               FROM unnest(%s) u(id INT, var1 INT)""", (data,))

ومع ذلك ، هو يمكن أن تكون صعبة مع بيانات كبيرة للغاية.

سؤال مرتبط جدا: إدراج بالجملة مع Sqlalchemy orm


كل الطرق تؤدي إلى روما, ، لكن بعضها يعبر الجبال ، يتطلب عبارات ولكن إذا كنت ترغب في الوصول إلى هناك بسرعة ، فأخذ الطريق السريع.


في هذه الحالة ، يقوم الطريق السريع باستخدام execute_batch () ميزة PSYCOPG2. الوثائق تقول أنها الأفضل:

التنفيذ الحالي ل executemany() هو (باستخدام بخس خيري للغاية) لا يؤدي بشكل خاص. يمكن استخدام هذه الوظائف لتسريع التنفيذ المتكرر لبيان مقابل مجموعة من المعلمات. من خلال تقليل عدد مستديرة الخادم ، يمكن أن يكون الأداء أوامر من حيث الحجم أفضل من استخدام executemany().

في الاختبار الخاص بي execute_batch() هو ما يقرب من مرتين بالسرعة مثل executemany(), ، ويعطي خيار تكوين Page_size لمزيد من التغيير والتبديل (إذا كنت ترغب في الضغط على آخر 2-3 ٪ من الأداء من برنامج التشغيل).

يمكن تمكين نفس الميزة بسهولة إذا كنت تستخدم SQLAlchemy عن طريق الإعداد use_batch_mode=True كمعلمة عند إنشاء مثيل للمحرك مع create_engine()

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top