Psycopg2 ، postgresql ، python: أسرع طريقة إلى الإلغاء بالجملة
-
20-09-2019 - |
سؤال
أنا أبحث عن الطريقة الأكثر فاعلية لإلغاء بعض الملايين من tuples في قاعدة بيانات. أنا أستخدم Python و PostgreSQL و PSYCOPG2.
لقد أنشأت قائمة طويلة من tulpes يجب إدراجها في قاعدة البيانات ، وأحيانًا مع المعدلات مثل الهندسة Simplify
.
الطريقة الساذجة للقيام بذلك ستكون تنسيق قائمة على قائمة INSERT
البيانات ، ولكن هناك ثلاث طرق أخرى قرأتها:
- استخدام
pyformat
نمط الربط للإدراج حدودي - استخدام
executemany
في قائمة tuples ، و - باستخدام كتابة النتائج إلى ملف واستخدام
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()