PDA

View Full Version : بالا بردن سرعت در هنگام ذخیره انباشت داده در ADO؟



SAASTN
جمعه 27 فروردین 1389, 03:21 صبح
سلام
من توی یه برنامه می خوام حجم زیادی از اطاعات رو یکجا توی یه دیتابیس access بنویسم، مثلا 50000 رکورد در یکبار اجرای فرمان. که این کار باعث بوجود اومدن مکث های چند ثانیه ای یا بعضا چند دقیقه ای میشه. با DisableControls تونستم سرعت خوندن این اطلاعات رو بین 50 تا 70 درصد کاهش بدم، اما موقع نوشتن اطلاعات تاثیر 5 تا حداکثر 10 درصدی داره. می خواستم بدونم روش دیگه ای برای افزایش سرعت درج هست؟ مثلا درج چند سطر به صورت یکجا؟
ضمنا من هیچ کنترلی رو به جداولم متصل نکردم و فقط از این جداول برای نوشتن و خوندن اطلاعات استفاده می کنم (فعلا امکان استفاده از روش دیگه ای رو ندارم).

ضمنا آیا تو نوشتن رکورد ها تفاوتی بین از insert و append و apppendrecord وجود داره یا نه، بصورت نظری یا عملی.

متشکرم

vcldeveloper
جمعه 27 فروردین 1389, 14:16 عصر
مثلا 50000 رکورد در یکبار اجرای فرمان.
50000 رکورد در یک بار اجرای چه فرمانی؟ در یک بار اجرای یک دستور SQL؟

سرعت اجرای فرامین مربوط به بانک اطلاعاتی ارتباط مستقیمی با قابلیت های موتور بانک اطلاعاتی موجود، و طراحی بانک اطلاعاتی توسط شما داره. طراحی بهینه جداول، ارتباطات شان، و Indexگزاری مناسب تا حدود زیادی موجب افزایش سرعت میشند. اما اینها وابسته به سناریوهای مورد استفاده هستند؛ یعنی بهینه سازی ها با توجه به نوع کاری که شما با بانک انجام میدید، و درخواست هایی که ازش دارید، صورت می گیرند.

SAASTN
جمعه 27 فروردین 1389, 21:13 عصر
50000 رکورد در یک بار اجرای چه فرمانی؟ در یک بار اجرای یک دستور SQL؟
خیر، مسئله اصلا SQL نیست. اصلا ارتباطی بین جداول وجود نداره و برنامه هم قرار نیست هیچ فرمان SQLی رو اجرا کنه یا اطلاعات رو مثلا در یه DBGrid نمایش بده. فقط 50000 رکورد قراره یکجا از داخل یه آرایه به داخل دیتابیس انتقال پیدا کنه. در جای دیگه هم قراره همین حجم اطلاعات از دیتابیس به داخل آرایه انتقال پیدا کنه. یه چیزی شبیه به expot کردن اطلاعات برای استفاده در جای دیگه. فعلا راهی هم غیر از access ندارم.
با این تفاسیر راهی برای افزایش سرعت خوندن و خصوصا نوشتن اطلاعات هست؟

Felony
جمعه 27 فروردین 1389, 21:29 عصر
من یه فکری به ذهنم رسید که تست هم نکردم ، شما اگر خواستی تست کن نتیجه رو بگو ، اگر جدولی که تو بانک اکسس داری از قبل مقدار داشه باشه ( مثلا 5000 تا رکورد با مقدار 0 یا X یا ... ) شاید بشه با چند تا نخ سرعت درج رو بالا برد ، به این صورت که مثلا 5 تا نخ تو برنامه میسازی و به هر کودوم 1000 تا رکورد میدی اضافه کنه ، از 1 تا 1000 = نخ 1 ، از 1001 تا 2000 = نخ 2 ، از 2001 تا 3000 = نخ 3 الی آخر ... ، اینطوری همزمان 5 تا نخ دارن 5000 تا رکورد رو درج میکنن و به صورت تئوری باید تقریبا به اندازه درج 1000 تا رکورد زمان ببره !

البته همه اینها یه نظریه بود ، باید تست بشه ...

SAASTN
جمعه 27 فروردین 1389, 21:48 عصر
مسئله اینه که رکورد ها کم هم می تونن باشن.
تست می کنم ببینم درج رکورد خالی سرعتش از درج اطلاعات بیشتر هست یا نه.

vcldeveloper
جمعه 27 فروردین 1389, 23:06 عصر
اصلا ارتباطی بین جداول وجود نداره و برنامه هم قرار نیست هیچ فرمان SQLی رو اجرا کنه
تمام کدهایی که به صورت متدهای Insert, Append, Edit, Delete و غیره در Dataset استفاده می کنید، منجر به تولید کد SQL میشند. برای طراحی بانک هم لازم نیست حتما جداولتون با هم مرتبط باشند. Indexهای بیخود و غیر ضروری، یا فراموش کردن Indexهای ضروری هر کدام می تونند به شدت سرعت عملیات ها روی جدول را کاهش بدند.


فقط 50000 رکورد قراره یکجا از داخل یه آرایه به داخل دیتابیس انتقال پیدا کنه.
وقتی میگید قراره یک جا به داخل دیتابیس انتقال پیدا کنه، یعنی کل 50000 رکورد را در داخل یک دستور SQL بزرگ قرار بدید، و آن دستور را اجرا کنید. اگر کاری غیر از این می کنید (مثلا استفاده از متدهای Insert یا Append) در اون صورت شما دارید چیزی رو به داخل بانک یکجا منتقل نمی کنید، بلکه دارید یک سری کدها را 50000 بار تکرار می کنید.

یک روش بالا بردن سرعت برای این کاری که شما دارید انجام میدید این هست که به جای استفاده از AdoTable یا AdoQuery، از AdoCommand استفاده کنید، و مجموعه رکوردهایی که باید اضافه بشند را به بخش های کوچکتر، مثلا دسته های 50 تایی تقسیم کنید، و هر دسته 50 تایی را با یک دستور SQL از طریق AdoCommand به بانک ارسال کنید. اینطوری هم تعداد اتصالات تون به بانک کاهش پیدا میکنه، هم بابت هر Insert یک بار Dataset داخل برنامه تان Refresh نمیشه.

اگر ارتباطی بین رکوردهای Insert شده وجود نداره، و لزومی به رعایت ترتیب خاصی نیست، یک راه دیگه همونه که ارسال دسته های رکورد را از طریق Threadهای مختلف انجام بدید. البته تصور نکنید که هر چی تعداد Threadها بیشتر باشه، سرعت برنامه شما بیشتر میشه! مدیریت غلط Threadها و ایجاد Threadهای بیخود خودش میتونه موجب کاهش سرعت بشه!

MFiRE
یک شنبه 29 فروردین 1389, 01:27 صبح
مسئله اینه که رکورد ها کم هم می تونن باشن.

خب اين كه خيلي ساده اس، تعداد ركورد ها رو تقسيم بر تعداد تردهايي كه ميخوايد داشته باشد بكنيد.

ولي سرعتي كه مده نظرتون هست، چقدره ؟ كمتر از يك دقيقه ؟
در حال حاضر يه پروژه دارم كه يه قسمتش از پارادوكس استفاده كردم. بايد يكسري ركورد رو از فايل هاي متني استخراج كنم و متن هاي دريافتي رو از هم جدا كنم و به بانك اضافه كنم.

در كل بيش از 100 فايل براي استخراج اطلاعات وجود داشت و الان كه تست كردم تويه 55 ثانيه تونست بيش از 47 هزار ركورد رو به بانك اضافه كنه.

اول از دستورات SQL استفاده كردم ولي كُند بود. بعد، از Insert كامپوننته Table استفاده كردم كه سرعتش بالاتر بود.

درج كردن اين 50000 ركورد، در برنامه تون چقدر طول ميكشه ؟

SAASTN
دوشنبه 30 فروردین 1389, 01:04 صبح
مجموعه رکوردهایی که باید اضافه بشند را به بخش های کوچکتر، مثلا دسته های 50 تایی تقسیم کنید، و هر دسته 50 تایی را با یک دستور SQL از طریق AdoCommand به بانک ارسال کنید.
ممکنه یه نمونه کد قرار بدین؟


تعداد ركورد ها رو تقسيم بر تعداد تردهايي كه ميخوايد داشته باشد بكنيد.
درست متوجه نشدم؟ من منظورم این بود که اگه از قبل 50000 تا رکورد خالی توی جدول بذارم ممکنه مجبور شم 45000 تاشو بعدا پاک کنم که اینم خوش یه سرباره.

درج كردن اين 50000 ركورد، در برنامه تون چقدر طول ميكشه ؟
49300 رکور (6 فیلد integer) در 1دقیقه و 3ثانیه
برای فایل های بزرگتر که رکورداشو نشمردم تا 6 دقیقه 30ثانیه هم ثبت شده که واقعا آزاردهندست!

البته این زمان حتما خیلی به مشخصات سخت افزار بستگی داره و احتمالا مقایسه زمان من با زمان شما خیلی قابل اتکا نیست.
اما نظرا access باید سریعتر از paradox باشه. دوستان کسی این دو رو مقایسه کرده؟

MFiRE
دوشنبه 30 فروردین 1389, 02:00 صبح
کم هم می تونن باشن.

درست متوجه نشدم؟ من منظورم این بود که اگه از قبل 50000 تا رکورد خالی توی جدول بذارم ممکنه مجبور شم 45000 تاشو بعدا پاک کنم که اینم خوش یه سرباره.
براي اينكار هم ميتونيد اول چك كنيد كه ركوردتون خالي نباشه.

مشخصات سيستم من :
پردازنده : Intel 2.4 Celeron (افتضاحه)
حافظه : 1 گيگ (بدرد نخوره)
بقيه اش هم مثله دوتايه بالايي جالب نيست...

8 يا 9 تا فيلد داره (Str,int)، چند تا عمليات والفجري هم رويه ركورد ها انجام ميده، بعد به بانك اضافه ميكنه.

ولي خودتون تست كنيد، ببينيد با بانك پارادوكس چطور عمل ميكنه.
سعي كنيد يك بار با Query و يك بار هم با Table.Insert اطلاعات رو به بانكتون اضافه كنيد.

موفق و پيروز باشيد

vcldeveloper
دوشنبه 30 فروردین 1389, 03:07 صبح
ولي خودتون تست كنيد، ببينيد با بانك پارادوكس چطور عمل ميكنه.
فیلد Image و بانک Paradox؟!! بنده خدا Paradox در Textاش مونده، و برای Textهای ذخیره شده باید همش دست به دعا باشید که فایل بانک تون خراب نشه، دیگه برای داده باینری حجیم جای خود دارد!


ممکنه یه نمونه کد قرار بدین؟
من نمی دونم داده های شما چطور ذخیره شدند و حاوی چه چیزهایی هستند. کار ساده هست، شما روی عناصر آرایه تان در یک حلقه حرکت کنید، و برای هر عنصر، داده های ذخیره شده در آن را بخوانید، و به یک String که قرار هست دستور INSERT INTO مربوط به AdoCommand شما را تشکیل بده، اضافه کنید.
هر 50 تا (یا هر چندتایی که دوست داشتید) عنصر که داده هایشان به دستور SQL مربوطه اضافه شدند، دستور SQL ساخته شده را به خصوصیت SQL مربوط به AdoCommand اختصاص بدید، و آن را Execute کنید. بین ترتیب، با هر بار Execute شدن، همان تعداد رکورد یکجا به جدول اضافه میشند.

برای افزایش سرعت هم می تونید این کار را از طریق چند Thread انجام بدید، یعنی هر Thread سهم خودش از عناصر آرایه را بگیره، و روی آنها حرکت کنه، دستور یا دستورات SQL مناسب را بر اساس آن داده ها ایجاد کنه، و با AdoCommand خودش آن دستور را به بانک ارسال کنه.

جواد ملاولی
دوشنبه 30 فروردین 1389, 05:42 صبح
با DisableControls تونستم سرعت خوندن این اطلاعات رو بین 50 تا 70 درصد کاهش بدم
در مورد DisableControls یه کم توضیح می خواستم.

حمیدرضاصادقیان
دوشنبه 30 فروردین 1389, 08:12 صبح
در مورد DisableControls یه کم توضیح می خواستم.

DisableControls (http://delphi.about.com/od/database/l/aa040301b.htm)

----------------------------------------
من اگر درست متوجه شده باشم شما ابتدا از یک فایل محتویات اونو به داخل ارایه میریزید بعد از داخل ارایه به دیتابیس منتقل میکنید. خوب اگر به این صورت هست شما به جای اینکه داخل ارایه بریزید محتویات فایل را با دستور Bulk Copy به داخل sqlمنتقل کنید که این فکر کنم سریعترین راه باشه.
موفق باشید

SAASTN
چهارشنبه 01 اردیبهشت 1389, 02:43 صبح
با تشکر فراوان از تمام اساتید


کار ساده هست، شما روی عناصر آرایه تان در یک حلقه حرکت کنید، و برای هر عنصر، داده های ذخیره شده در آن را بخوانید، و به یک String که قرار هست دستور INSERT INTO مربوط به AdoCommand شما را تشکیل بده، اضافه کنید.

همین؟! به ازای هر رکورد یه insert into بنویسم؟ یه همچین کاری می تونه سرعت رو افزایش بده؟ چون بهر صورت تعداد insert هایی که باید انجام بشه از نظر access تغییر نکرده. من تصور می کردم که به نوعی میشه با یک کد sql چند رکورد رو پشت سرهم insert کرد.



من اگر درست متوجه شده باشم شما ابتدا از یک فایل محتویات اونو به داخل ارایه میریزید بعد از داخل ارایه به دیتابیس منتقل میکنید
خیر دوست عزیز، مسئله اینه که اساسا در ابتدا جدول و دیتابیسی وجود نداره. مسئله خروجی دادن به یک برنامه و ورودی گرفتن از اون هست. برنامه حاضر هیچ دیتابیسی نداره و فقط می خوام بخشی از اطلاعات که در چند آرایه وجود دارن رو در قالب یک فایل access در اختیار یه برنامه دیگه بذارم. از طرفی اون برنامه هم یک خروجی access تولید می کنه و من باید جداول رو بخونم و مستقیم به آرایه ها انتقال بدم.

vcldeveloper
چهارشنبه 01 اردیبهشت 1389, 13:12 عصر
به ازای هر رکورد یه insert into بنویسم؟ یه همچین کاری می تونه سرعت رو افزایش بده؟ چون بهر صورت تعداد insert هایی که باید انجام بشه از نظر access تغییر نکرده. من تصور می کردم که به نوعی میشه با یک کد sql چند رکورد رو پشت سرهم insert کرد.خیر:
http://blog.sqlauthority.com/2008/07/02/sql-server-2008-insert-multiple-records-using-one-insert-statement-use-of-row-constructor/

البته روش سوم روی MySQL و SQL Server 2008 جواب میده، شاید نتونید از روش سوم ارائه شده در اون لینک در Access استفاده کنید، ولی به احتمال زیاد روش دوم برای Insert رو بتونید توی Access استفاده کنید.

hamid_massaelly
یک شنبه 12 اردیبهشت 1389, 09:23 صبح
یک تابع String بنویس که اول خود تابع به صورت درخواست Query برات بسازه بعد یکبار Query را برای Sql ارسال کن.

SAASTN
جمعه 21 خرداد 1389, 23:22 عصر
سلام، ببخشید که تاپیکو بالا میارم
یه مدت (یعنی مدت زیادی) سرم خیلی شلوغ بود نتونستم رو موضوع کار کنم. روش MultiThreding رو پیاده کردم که جواب خوبی نداد، سرعت در حدود 10% بالا رفت. و جالب این که بالا بردن تعداد ترد ها نتیجه معکوس داره. روی سیستم من بهینه ترین وضعیت با دو ترد بود. با توجه به اینکه من تجربه زیادی تو MultiThreading ندارم دوستان اگه زحمت بکشن یه بررسی بکنن ممنون می شم. به هر صورت اگه کدم اشتباه فاحشی نداشته باشه کلاسی که آماده کردم برای تقسیم یک کار (در صورتی که نیاز به Synch نباشه) بین تعداد دلخواهی ترد به درد می خوره.
قبلا ممنونم

vcldeveloper
شنبه 22 خرداد 1389, 03:44 صبح
جالب این که بالا بردن تعداد ترد ها نتیجه معکوس داره. روی سیستم من بهینه ترین وضعیت با دو ترد بود.
من کد رو دانلود نکردم که ببینم چی هست؛ ولی درباره Multi-threading، همونطور که خودتون به صورت تجربی بهش رسیدید، افزایش تعداد Threadها لزوما به معنای افزایش کارایی برنامه نیست، و حتی میتونه منجر به کاهش کارایی بشه. بهترین حالتش یک Thread برای هر هسته CPU هست.

Saeid59_m
دوشنبه 24 خرداد 1389, 21:13 عصر
یه پیشنهاد دارم .
عناصر آرایه شما چیه ؟
مثلاً اگر عدد باشه
با این اعداد یک رشته درست کنید مثل
Str := ' 125 , 100 , 250 , 600 , 188 , ...
یا یه چیزی شبیه این بعد این رکورد رو توی بانک ذخیره کنید اینطوری یک یا چند رکورد بیشتر ذخیره نمی شه و سرعت هم بالا می ره .

SAASTN
سه شنبه 25 خرداد 1389, 01:23 صبح
عناصر آرایه شما چیه ؟
مثلاً اگر عدد باشه ...
خیر، متاسفانه رکوردهای پیچیده ای از فیلدهای متعدد و انواع داده ای متفاوت.
تصور نمی کنم ذخیره یه string بجای integer معادل خیلی بهینه و معقول باشه. هرچند نگهداری اطلاعات بصورت ترکیبی یک حسن بزرگ داره. اونم کاهش تعداد رکورد ها در جدوله. توی access وقتی تعداد رکورد ها از حدود 70 هزار میگذره یکباره سرعت درج بطور وحشتناکی کاهش پیدا می کنه. و با بررسی که کردم می تونم بگم که حجم اطلاعات هر رکورد خیلی در این مسئله تاثیر نداره و مهمترین فاکتور همون تعداد رکورد هاست، البته حجم رکورد بی تاثیر هم نیست. اما در هر صورت تصور نمی کنم خود تولید رشته، ذخیره و بازیابی اون رشته و در نهایت پارس کردن رشته، در مجموع زمان کمتری از زمان موجود ببره.