سوال:
من دو جدول در یک پایگاه داده PostgreSQL دارم که هرکدام ستونهایی دارند، از جمله:
جدول A:
| IdA | IdTokenStore | CodeIntegerA |
|---|---|---|
| 789 | (details, “{“”token-string-123″”}”) |
جدول B:
| IdB | IdTokenImport | CodeIntegerB |
|---|---|---|
| 456 | token-string-234 | 1234 |
هر کدام از این جداول 10 میلیون رکورد دارند.
چه کوئری SQL میتواند مقدار CodeIntegerB را از جدول B به ستون CodeIntegerA در جدول A کپی کند، به شرطی که IdTokenStore (متن) شبیه به IdTokenImport باشد؟ آیا راه خاصی برای انجام این کار با توجه به تعداد بالای رکوردها وجود دارد؟
چگونه میتوان این کار را با استفاده از پایتون در یک نوتبوک Jupyter به صورت مرحلهای انجام داد، به طوری که بتوانید این عملیات را به صورت تکهای انجام دهید، مثلاً 500,000 یا 1 میلیون رکورد در هر مرحله – مخصوصاً اگر تعداد رکوردها حتی بیشتر از این باشد؟
پاسخ:
برای انجام این عملیات با توجه به حجم بالای دادهها، چندین راهکار وجود دارد. ابتدا کوئری SQL را ارائه میدهیم و سپس به روش مرحلهای با پایتون میپردازیم.
1. کوئری SQL برای بهروزرسانی دادهها:
برای کپی کردن مقادیر از CodeIntegerB در جدول B به CodeIntegerA در جدول A، میتوانید از کوئری زیر استفاده کنید:
UPDATE TableA SET CodeIntegerA = TableB.CodeIntegerB FROM TableB WHERE TableA.IdTokenStore::text LIKE '%' || TableB.IdTokenImport || '%';
این کوئری از عملگر LIKE برای تطبیق IdTokenStore با IdTokenImport استفاده میکند و سپس مقادیر را بهروزرسانی میکند. با این حال، برای دادههای بسیار بزرگ (مثل 10 میلیون رکورد) ممکن است اجرای این کوئری زمانبر باشد.
2. انجام عملیات مرحلهای با استفاده از پایتون:
برای انجام این کار به صورت مرحلهای در یک نوتبوک Jupyter، میتوانید از کتابخانه psycopg2 یا SQLAlchemy برای ارتباط با PostgreSQL استفاده کنید. در ادامه نمونه کد با استفاده از psycopg2 ارائه شده است:
import psycopg2
# اتصال به پایگاه داده
conn = psycopg2.connect(
dbname="your_db_name",
user="your_username",
password="your_password",
host="your_host",
port="your_port"
)
cursor = conn.cursor()
# تعیین اندازه بخشها (batch size)
batch_size = 500000
offset = 0
while True:
# کوئری برای بهروزرسانی به صورت مرحلهای
update_query = f"""
UPDATE TableA
SET CodeIntegerA = TableB.CodeIntegerB
FROM TableB
WHERE TableA.IdTokenStore::text LIKE '%' || TableB.IdTokenImport || '%'
LIMIT {batch_size} OFFSET {offset};
"""
cursor.execute(update_query)
conn.commit()
# اگر هیچ رکوردی بهروزرسانی نشده باشد، از حلقه خارج میشویم
if cursor.rowcount == 0:
break
offset += batch_size
# بستن اتصال به پایگاه داده
cursor.close()
conn.close()
نکات:
- اندازه بخشها (Batch Size): با توجه به منابع سیستم و اندازه جداول، ممکن است لازم باشد
batch_sizeرا تنظیم کنید. در اینجا 500,000 رکورد به عنوان نمونه استفاده شده است. - حلقه While: این حلقه بهروزرسانی را در بخشهای مشخص شده انجام میدهد و تا زمانی که تمامی رکوردها بهروزرسانی شوند، ادامه مییابد.
- بستن اتصال: حتماً پس از پایان عملیات، اتصال به پایگاه داده را ببندید.
این روش به شما اجازه میدهد تا به صورت مرحلهای و با مدیریت بهتری از منابع سیستم، عملیات بهروزرسانی را انجام دهید.
پاسخ دوم
دو جدول با ستونهایی مشابه در یک پایگاه داده PostgreSQL داریم:
جدول A:
| IdA | IdTokenStore | CodeIntegerA |
|---|---|---|
| 789 | (جزئیات، “{“”token-string-123″”}”) | خالی |
جدول B:
| IdB | IdTokenImport | CodeIntegerB |
|---|---|---|
| 456 | token-string-234 | 1234 |
هر دو جدول تقریبا 10 میلیون رکورد دارند.
چگونه میتوانیم مقدار CodeIntegerB از جدول B را به CodeIntegerA در جدول A کپی کنیم، به شرطی که IdTokenStore (متن) شبیه به idTokenImport باشد؟ با توجه به حجم بالای دادهها، چه روش خاصی برای انجام این کار وجود دارد؟
چگونه میتوانیم این کار را با پایتون در یک نوتبوک Jupyter انجام دهیم تا بتوانیم آن را به صورت بخشی انجام دهیم، مثلا 500 هزار یا 1 میلیون رکورد در هر بار – به خصوص اگر تعداد رکوردها حتی بیشتر باشد؟
پاسخ:
روش SQL:
برای انجام این کار با SQL، میتوانید از یک آپدیت با زیرکوئری استفاده کنید:
SQL
UPDATE table_a a SET codeintegera = ( SELECT codeintegerb FROM table_b b WHERE a.idtokenstore LIKE '%' || b.idtokenimport || '%' LIMIT 1 );
توجه داشته باشید که LIKE برای مقایسه رشتهها استفاده میشود و % یک کاراکتر وحشی است. این کوئری ممکن است برای میلیونها رکورد کند باشد.
روش پایتون:
برای بهبود عملکرد، میتوانید از پایتون برای پردازش دادهها به صورت بخشی استفاده کنید. این روش همچنین به شما امکان میدهد کنترل بیشتری بر روی فرآیند داشته باشید.
Python
import psycopg2
def copy_data(conn, chunk_size=500000):
cursor = conn.cursor()
offset = 0
while True:
cursor.execute("""
SELECT a.ida, b.codeintegerb
FROM table_a a
JOIN table_b b ON a.idtokenstore LIKE '%' || b.idtokenimport || '%'
LIMIT %s OFFSET %s
""", (chunk_size, offset))
rows = cursor.fetchall()
if not rows:
break
update_values = [(row[1], row[0]) for row in rows]
cursor.executemany("UPDATE table_a SET codeintegera = %s WHERE ida = %s", update_values)
conn.commit()
offset += chunk_size
# Example usage:
conn = psycopg2.connect(database="your_database", user="your_user", password="your_password", host="your_host")
copy_data(conn)
conn.close()
این کد دادهها را به بخشهایی با اندازه مشخص تقسیم میکند و هر بخش را به روزرسانی میکند. این روش میتواند به طور قابل توجهی عملکرد را بهبود بخشد.
توجه:
- این کد یک مثال ساده است و ممکن است نیاز به تنظیمات اضافی برای محیط خاص شما داشته باشد.
- برای بهبود عملکرد بیشتر، میتوانید از پارامترهای اتصال PostgreSQL مانند
cursor_factory=psycopg2.extras.RealDictCursorاستفاده کنید. - در نظر داشته باشید که استفاده از
LIKEبا کاراکترهای وحشی میتواند عملکرد را کاهش دهد. اگر امکان پذیر است، از روشهای دقیقتر برای تطبیق رشتهها استفاده کنید.
همچنین میتوانید از ابزارهای تخصصی برای بارگذاری دادهها مانند pg_bulkload یا psycopg2.copy_from استفاده کنید که ممکن است در برخی موارد عملکرد بهتری داشته باشند.
The post Postgres + Python کپی میلیون ها رکورد داده appeared first on Tutorial24.ir.





