PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

پیشنهاد می‌کنم متن گزارش اولیه ولادیمیر سیتنیکوف در سال 2016 را بخوانید: «PostgreSQL و JDBC همه چیز را می‌فشارند»

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

عصر بخیر نام من ولادیمیر سیتنیکوف است. من 10 سال است که برای NetCracker کار می کنم. و من بیشتر اهل بهره وری هستم. همه چیز مربوط به جاوا، همه چیز مربوط به SQL همان چیزی است که من دوست دارم.

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

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

صحبت خواهیم کرد:

  • در مورد نمونه گیری داده ها
  • درباره ذخیره داده ها
  • و همچنین در مورد عملکرد.
  • و در مورد چنگک های زیر آب که در آنجا دفن شده اند.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

بیایید با یک سوال ساده شروع کنیم. یک ردیف از جدول را بر اساس کلید اصلی انتخاب می کنیم.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

پایگاه داده روی همان هاست قرار دارد. و تمام این کشاورزی 20 میلی ثانیه طول می کشد.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

این 20 میلی ثانیه خیلی زیاد است. اگر 100 درخواست از این قبیل داشته باشید، در هر ثانیه زمانی را صرف پیمایش این درخواست‌ها می‌کنید، یعنی ما در حال تلف کردن زمان هستیم.

ما دوست نداریم این کار را انجام دهیم و ببینیم پایگاه برای این کار چه چیزی به ما ارائه می دهد. پایگاه داده دو گزینه برای اجرای پرس و جو به ما ارائه می دهد.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

اولین گزینه یک درخواست ساده است. چه چیزی در مورد آن خوب است؟ این که می گیریم و می فرستیم و دیگر هیچ.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

https://github.com/pgjdbc/pgjdbc/pull/478

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

پرس و جو فوق گسترده چیزی است که در گزارش فعلی به آن نمی پردازیم. ما، شاید، چیزی از پایگاه داده می خواهیم و لیست آرزوهایی وجود دارد که به شکلی شکل گرفته است، یعنی این همان چیزی است که ما می خواهیم، ​​اما اکنون و در سال آینده غیرممکن است. بنابراین ما فقط آن را ضبط کردیم و به اطراف می رویم و افراد اصلی را تکان می دهیم.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

و کاری که می توانیم انجام دهیم پرس و جوی ساده و پرس و جوی گسترده است.

هر رویکرد چه ویژگی خاصی دارد؟

یک کوئری ساده برای اجرای یکباره خوب است. یک بار انجام شد و فراموش شد. و مشکل این است که فرمت داده های باینری را پشتیبانی نمی کند، یعنی برای برخی از سیستم های با کارایی بالا مناسب نیست.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

جستجوی گسترده - به شما امکان می دهد در تجزیه وقت صرفه جویی کنید. این همان کاری است که ما انجام دادیم و شروع به استفاده کردیم. این واقعاً به ما کمک کرد. صرفه جویی نه تنها در تجزیه وجود دارد. صرفه جویی در انتقال داده وجود دارد. انتقال داده ها در فرمت باینری بسیار کارآمدتر است.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

بیایید به سراغ تمرین برویم. این چیزی است که یک برنامه معمولی به نظر می رسد. این می تواند جاوا و غیره باشد.

ما بیانیه ایجاد کردیم. دستور را اجرا کرد. نزدیک ایجاد شد. اشتباه اینجا کجاست؟ مشکل چیه؟ مشکلی نیست این چیزی است که در همه کتاب ها آمده است. این طوری باید نوشت. اگر حداکثر کارایی را می خواهید، اینگونه بنویسید.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

اما عمل نشان داده است که این کار نمی کند. چرا؟ چون ما روش «بسته» داریم. و وقتی این کار را انجام می دهیم، از دیدگاه پایگاه داده معلوم می شود که مانند سیگاری است که با یک پایگاه داده کار می کند. گفتیم "پارس EXECUTE DEALLOCATE".

چرا این همه ایجاد و تخلیه اضافی بیانیه ها؟ هیچ کس به آنها نیاز ندارد. اما چیزی که معمولا در PreparedStatements اتفاق می افتد این است که وقتی آنها را می بندیم، همه چیز را در پایگاه داده می بندند. این چیزی نیست که ما می خواهیم.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

ما می خواهیم مانند افراد سالم با پایگاه کار کنیم. ما یک بار بیانیه خود را گرفتیم و آماده کردیم، سپس چندین بار آن را اجرا می کنیم. در واقع، بارها - این یک بار در کل عمر برنامه ها است - آنها تجزیه شده اند. و ما از همان عبارت id در REST های مختلف استفاده می کنیم. این هدف ماست.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

ما چگونه می توانیم به این دست پیدا کنیم؟

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

بسیار ساده است - نیازی به بستن عبارات نیست. ما آن را به این صورت می نویسیم: "آماده کردن" "اجرا".

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

اگر چنین چیزی را راه اندازی کنیم، مشخص است که چیزی در جایی سرریز خواهد شد. اگر واضح نیست، می توانید آن را امتحان کنید. بیایید یک معیار بنویسیم که از این روش ساده استفاده می کند. یک بیانیه ایجاد کنید. ما آن را روی برخی از نسخه‌های درایور راه‌اندازی می‌کنیم و متوجه می‌شویم که با از دست دادن تمام حافظه‌ای که داشت، خیلی سریع خراب می‌شود.

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

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

چگونه درست کار کنیم؟ برای این کار باید چکار کنیم؟

در واقعیت، برنامه ها همیشه عبارات را می بندند. در همه کتاب ها می گویند ببند وگرنه حافظه لو می رود.

و PostgreSQL نمی داند که چگونه کوئری ها را کش کند. لازم است که هر جلسه این کش را برای خود ایجاد کند.

و ما نمی خواهیم زمان را برای تجزیه تلف کنیم.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

و طبق معمول دو گزینه داریم.

گزینه اول این است که آن را می گیریم و می گوییم که بیایید همه چیز را در PgSQL بپیچیم. آنجا یک کش وجود دارد. همه چیز را ذخیره می کند. عالی خواهد شد. ما این را دیدیم. ما 100500 درخواست داریم. کار نمی کند. ما با تبدیل درخواست ها به رویه ها به صورت دستی موافقت نمی کنیم. نه نه.

ما یک گزینه دوم داریم - آن را بردارید و خودمان آن را برش دهیم. منابع را باز می کنیم و شروع به برش می کنیم. دیدیم و دیدیم. معلوم شد که انجام آن چندان دشوار نیست.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

https://github.com/pgjdbc/pgjdbc/pull/319

این در آگوست 2015 ظاهر شد. اکنون نسخه مدرن تری وجود دارد. و همه چیز عالی است. آنقدر خوب کار می کند که ما چیزی را در برنامه تغییر نمی دهیم. و ما حتی فکر کردن در جهت PgSQL را متوقف کردیم، یعنی این برای ما کافی بود تا تمام هزینه های سربار را تقریباً به صفر کاهش دهیم.

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

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

ممکن است بپرسید - اعداد کجا هستند؟ چی میگیری؟ و در اینجا من اعداد را نمی دهم ، زیرا هر درخواست خاص خود را دارد.

پرس و جوهای ما به گونه ای بود که حدود 20 میلی ثانیه را برای تجزیه پرس و جوهای OLTP صرف کردیم. 0,5 میلی ثانیه برای اجرا، 20 میلی ثانیه برای تجزیه وجود داشت. درخواست - 10 کیلو بایت متن، 170 خط طرح. این یک درخواست OLTP است. این درخواست 1، 5، 10 خط، گاهی اوقات بیشتر.

اما ما اصلا نمی خواستیم 20 میلی ثانیه را تلف کنیم. ما آن را به 0 کاهش دادیم. همه چیز عالیه

چه چیزی را می توانید از اینجا بردارید؟ اگر جاوا دارید، پس نسخه مدرن درایور را می گیرید و خوشحال می شوید.

اگر به زبان دیگری صحبت می کنید، پس فکر کنید - شاید شما هم به این نیاز دارید؟ زیرا از نظر زبان نهایی، مثلاً اگر PL 8 یا LibPQ داشته باشید، برای شما واضح نیست که وقت خود را صرف اجرا، تجزیه و تحلیل نمی کنید، و این ارزش بررسی را دارد. چگونه؟ همه چیز رایگان است.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

با این تفاوت که خطاها و برخی ویژگی ها وجود دارد. و ما در حال حاضر در مورد آنها صحبت خواهیم کرد. بیشتر آن در مورد باستان شناسی صنعتی است، در مورد آنچه که ما پیدا کردیم، چیزی که با آن برخورد کردیم.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

اگر درخواست به صورت پویا ایجاد شود. اتفاق می افتد. یک نفر رشته ها را به هم می چسباند و در نتیجه یک پرس و جوی SQL ایجاد می شود.

چرا او بد است؟ بد است زیرا هر بار با یک رشته متفاوت روبرو می شویم.

و هش کد این رشته متفاوت باید دوباره خوانده شود. این واقعاً یک کار CPU است - یافتن یک متن درخواست طولانی حتی در یک هش موجود چندان آسان نیست. بنابراین، نتیجه گیری ساده است - درخواست ایجاد نکنید. آنها را در یک متغیر ذخیره کنید. و شادی کن.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

مشکل بعدی انواع داده ها مهم هستند. ORM هایی وجود دارند که می گویند مهم نیست که چه نوع NULL وجود دارد، بگذارید نوعی وجود داشته باشد. اگر Int، آنگاه می گوییم setInt. و اگر NULL باشد، بگذارید همیشه VARCHAR باشد. و در نهایت چه فرقی می کند NULL وجود دارد؟ خود پایگاه داده همه چیز را درک خواهد کرد. و این عکس کار نمی کند.

در عمل، پایگاه داده اصلا اهمیتی نمی دهد. اگر بار اول گفتید که این یک عدد است و بار دوم گفتید که یک VARCHAR است، پس استفاده مجدد از دستورات آماده شده توسط سرور غیرممکن است. و در این مورد، ما باید بیانیه خود را دوباره ایجاد کنیم.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

اگر همان پرس و جو را اجرا می کنید، مطمئن شوید که انواع داده ها در ستون شما اشتباه گرفته نمی شود. شما باید مراقب NULL باشید. این یک خطای متداول است که پس از شروع استفاده از PreparedStatements با آن مواجه شدیم

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

باشه روشن شد شاید راننده را برده اند. و بهره وری کاهش یافت. اوضاع بد شد

چگونه این اتفاق می افتد؟ آیا این یک خطا است یا یک عملکرد؟ متأسفانه، نمی توان فهمید که آیا این یک باگ است یا یک ویژگی. اما یک سناریوی بسیار ساده برای بازتولید این مشکل وجود دارد. او کاملاً غیرمنتظره به ما کمین کرد. و شامل نمونه برداری به معنای واقعی کلمه از یک جدول است. ما البته از این قبیل درخواست ها بیشتر داشتیم. به عنوان یک قاعده، آنها شامل دو یا سه جدول بودند، اما چنین سناریوی پخش وجود دارد. هر نسخه ای را از پایگاه داده خود بگیرید و آن را پخش کنید.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

https://gist.github.com/vlsi/df08cbef370b2e86a5c1

نکته این است که ما دو ستون داریم که هر کدام ایندکس شده است. یک میلیون ردیف در یک ستون NULL وجود دارد. و ستون دوم فقط شامل 20 خط است. وقتی بدون متغیرهای محدود اجرا می کنیم، همه چیز به خوبی کار می کند.

اگر اجرا را با متغیرهای محدود شروع کنیم، یعنی "?" را اجرا می کنیم. یا "1 دلار" برای درخواست ما، در نهایت چه چیزی دریافت می کنیم؟

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

https://gist.github.com/vlsi/df08cbef370b2e86a5c1

اجرای اول همان طور است که انتظار می رود. دومی کمی سریعتر است. چیزی ذخیره شده بود. سوم، چهارم، پنجم. سپس بنگ - و چیزی شبیه به آن. و بدترین چیز این است که این اتفاق در اعدام ششم می افتد. چه کسی می دانست که باید دقیقاً شش اعدام انجام شود تا بفهمد برنامه واقعی اعدام چیست؟

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

مقصر کیست؟ چی شد؟ پایگاه داده شامل بهینه سازی است. و به نظر می رسد برای مورد عمومی بهینه شده است. و، بر این اساس، با شروع از نقطه ای، او به یک برنامه عمومی تغییر می کند، که، متأسفانه، ممکن است متفاوت باشد. ممکن است یکسان باشد، یا ممکن است متفاوت باشد. و نوعی مقدار آستانه وجود دارد که منجر به این رفتار می شود.

درباره آن چکار میتونید بکنید؟ در اینجا، البته، فرض کردن چیزی دشوارتر است. یک راه حل ساده وجود دارد که ما از آن استفاده می کنیم. این +0، OFFSET 0 است. مطمئناً شما چنین راه حل هایی را می شناسید. ما فقط آن را می گیریم و "+0" را به درخواست اضافه می کنیم و همه چیز خوب است. بعدا بهت نشون میدم

و گزینه دیگری وجود دارد - به برنامه ها با دقت بیشتری نگاه کنید. توسعه دهنده نه تنها باید یک درخواست بنویسد، بلکه باید 6 بار بگوید "تشریح تجزیه و تحلیل". اگر 5 باشد کار نمی کند.

و یک گزینه سوم وجود دارد - نامه ای به pgsql-hackers بنویسید. من نوشتم، اما هنوز مشخص نیست که این یک باگ است یا یک ویژگی.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

https://gist.github.com/vlsi/df08cbef370b2e86a5c1

در حالی که ما به این فکر می کنیم که آیا این یک باگ است یا یک ویژگی، بیایید آن را برطرف کنیم. بیایید درخواست خود را بپذیریم و "+0" را اضافه کنیم. همه چیز خوب است. دو نماد و حتی لازم نیست به این فکر کنید که چگونه است یا چیست. بسیار ساده. ما به سادگی پایگاه داده را از استفاده از شاخص در این ستون منع کردیم. ما در ستون "+0" ایندکس نداریم و بس، پایگاه داده از ایندکس استفاده نمی کند، همه چیز خوب است.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

این قانون 6 توضیح است. حالا در نسخه های فعلی اگر متغیرهای محدودی دارید باید 6 بار این کار را انجام دهید. اگر متغیرهای محدودی ندارید، این کاری است که ما انجام می دهیم. و در نهایت دقیقاً این درخواست است که ناکام می ماند. این چیز پیچیده ای نیست.

به نظر می رسد، چقدر ممکن است؟ یک اشکال اینجا، یک اشکال آنجا. در واقع، اشکال در همه جا وجود دارد.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

بیایید نگاه دقیق تری بیندازیم. به عنوان مثال، ما دو طرحواره داریم. طرح A با جدول S و نمودار B با جدول S. Query - داده ها را از یک جدول انتخاب کنید. در این صورت چه خواهیم داشت؟ خطا خواهیم داشت. همه موارد فوق را خواهیم داشت. قانون این است - یک اشکال در همه جا وجود دارد، ما همه موارد فوق را خواهیم داشت.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

حال سوال این است: "چرا؟" به نظر می رسد مستنداتی وجود دارد که نشان می دهد اگر یک طرحواره داریم، یک متغیر "search_path" وجود دارد که به ما می گوید کجا باید جدول را جستجو کنیم. به نظر می رسد که یک متغیر وجود دارد.

مشکل چیه؟ مشکل این است که عبارات آماده شده توسط سرور مشکوک نیستند که search_path توسط شخصی قابل تغییر باشد. این مقدار، همانطور که بود، برای پایگاه داده ثابت می ماند. و برخی از قسمت ها ممکن است معانی جدیدی دریافت نکنند.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

البته این بستگی به نسخه ای دارد که روی آن تست می کنید. بستگی به تفاوت جدی جداول شما دارد. و نسخه 9.1 به سادگی کوئری های قدیمی را اجرا می کند. ممکن است نسخه‌های جدید باگ را پیدا کنند و به شما بگویند که باگ دارید.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

تنظیم search_path + دستورات آماده شده توسط سرور =
طرح کش نباید نوع نتیجه را تغییر دهد

چگونه آن را درمان کنیم؟ یک دستور العمل ساده وجود دارد - آن را انجام ندهید. در حین اجرای برنامه نیازی به تغییر search_path نیست. در صورت تغییر، بهتر است یک اتصال جدید ایجاد کنید.

می توانید بحث کنید، یعنی باز کنید، بحث کنید، اضافه کنید. شاید بتوانیم توسعه دهندگان پایگاه داده را متقاعد کنیم که وقتی شخصی مقداری را تغییر می دهد، پایگاه داده باید این موضوع را به مشتری بگوید: «ببینید، ارزش شما در اینجا به روز شده است. شاید لازم باشد عبارات را بازنشانی کنید و دوباره بسازید؟» اکنون پایگاه داده مخفیانه رفتار می کند و به هیچ وجه گزارش نمی دهد که عبارات در جایی در داخل تغییر کرده اند.

و من دوباره تاکید می کنم - این چیزی است که برای جاوا معمولی نیست. ما همان چیزی را در PL/pgSQL یک به یک خواهیم دید. اما در آنجا تکثیر خواهد شد.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

بیایید انتخاب داده های بیشتری را امتحان کنیم. ما انتخاب می کنیم و انتخاب می کنیم. ما یک جدول با یک میلیون ردیف داریم. هر خط یک کیلوبایت است. تقریبا یک گیگابایت داده. و ما یک حافظه کاری در ماشین جاوا 128 مگابایتی داریم.

ما همانطور که در همه کتاب ها توصیه شده است از پردازش جریانی استفاده می کنیم. یعنی resultSet را باز می کنیم و داده ها را از آنجا کم کم می خوانیم. آیا کار خواهد کرد؟ آیا از حافظه می افتد؟ کمی می خوانی؟ بیایید به پایگاه داده اعتماد کنیم، به Postgres اعتماد کنیم. ما آن را باور نمی کنیم. آیا ما از حافظه خارج خواهیم شد؟ چه کسی OutOfMemory را تجربه کرد؟ بعد از آن چه کسی توانست آن را درست کند؟ کسی موفق شد آن را درست کند.

اگر یک میلیون ردیف دارید، نمی توانید فقط انتخاب کنید. OFFSET/LIMIT مورد نیاز است. چه کسی برای این گزینه مناسب است؟ و چه کسی طرفدار بازی با autoCommit است؟

در اینجا، طبق معمول، غیر منتظره ترین گزینه صحیح می شود. و اگر به طور ناگهانی AutoCommit را خاموش کنید، کمک خواهد کرد. چرا اینطور است؟ علم در این مورد نمی داند.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

اما به طور پیش‌فرض، همه کلاینت‌هایی که به پایگاه داده Postgres متصل می‌شوند، کل داده‌ها را واکشی می‌کنند. PgJDBC نیز از این نظر مستثنی نیست و تمام سطرها را انتخاب می کند.

یک تغییر در تم FetchSize وجود دارد، یعنی می توانید در سطح یک عبارت جداگانه بگویید که در اینجا، لطفا داده ها را با 10، 50 انتخاب کنید. اما این کار تا زمانی که AutoCommit را خاموش نکنید، کار نمی کند. AutoCommit خاموش شد - شروع به کار می کند.

اما مرور کد و تنظیم setFetchSize در همه جا ناخوشایند است. بنابراین، ما تنظیماتی را ایجاد کردیم که مقدار پیش فرض را برای کل اتصال بیان می کند.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

این همان چیزی است که ما گفتیم. پارامتر پیکربندی شده است. و چه به دست آوردیم؟ اگر مقادیر کم را انتخاب کنیم، مثلاً اگر هر بار 10 ردیف را انتخاب کنیم، هزینه های سربار بسیار زیادی داریم. بنابراین، این مقدار باید در حدود صد تنظیم شود.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

البته، در حالت ایده‌آل، هنوز باید یاد بگیرید که چگونه آن را در بایت محدود کنید، اما دستور کار این است: defaultRowFetchSize را روی بیش از صد تنظیم کنید و خوشحال باشید.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

بیایید به درج داده ها برویم. درج آسان تر است، گزینه های مختلفی وجود دارد. به عنوان مثال، INSERT، VALUES. این گزینه خوبی است. می توانید بگویید "INSERT SELECT". در عمل هم همین است. هیچ تفاوتی در عملکرد وجود ندارد.

کتاب ها می گویند که شما باید یک دستور Batch را اجرا کنید، کتاب ها می گویند که می توانید دستورات پیچیده تری را با چند پرانتز اجرا کنید. و Postgres یک ویژگی فوق العاده دارد - می توانید COPY را انجام دهید، یعنی آن را سریعتر انجام دهید.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

اگر آن را اندازه گیری کنید، دوباره می توانید اکتشافات جالبی داشته باشید. چگونه می خواهیم این کار کند؟ ما می خواهیم دستورات غیر ضروری را تجزیه نکنیم و اجرا نکنیم.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

در عمل TCP این اجازه را به ما نمی دهد. اگر مشتری مشغول ارسال درخواست باشد، پایگاه داده در تلاش برای ارسال پاسخ به ما درخواست ها را نمی خواند. نتیجه نهایی این است که مشتری منتظر می ماند تا پایگاه داده درخواست را بخواند و پایگاه داده منتظر می ماند تا مشتری پاسخ را بخواند.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

و بنابراین مشتری مجبور است به صورت دوره ای یک بسته همگام سازی ارسال کند. تعاملات شبکه اضافی، اتلاف وقت اضافی.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوفو هر چه بیشتر آنها را اضافه کنیم، بدتر می شود. راننده کاملاً بدبین است و اغلب آنها را اضافه می کند، تقریباً هر 200 خط یک بار، بسته به اندازه خطوط و غیره.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

https://github.com/pgjdbc/pgjdbc/pull/380

این اتفاق می افتد که شما فقط یک خط را اصلاح می کنید و همه چیز 10 برابر سرعت می یابد. اتفاق می افتد. چرا؟ طبق معمول، یک ثابت مانند این قبلاً در جایی استفاده شده است. و مقدار "128" به معنای عدم استفاده از بچینگ است.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

مهار میکرو بنچمارک جاوا

خوب است که این در نسخه رسمی گنجانده نشده است. قبل از شروع انتشار کشف شد. تمام معانی من بر اساس نسخه های مدرن است.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

بیایید آن را امتحان کنیم. ما InsertBatch را به سادگی اندازه گیری می کنیم. ما InsertBatch را چندین بار اندازه می گیریم، یعنی یک چیز، اما مقادیر زیادی وجود دارد. حرکت فریبنده. همه نمی توانند این کار را انجام دهند، اما این یک حرکت بسیار ساده است، بسیار ساده تر از COPY.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

می توانید COPY را انجام دهید.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

و شما می توانید این کار را روی سازه ها انجام دهید. نوع پیش فرض کاربر را اعلام کنید، آرایه را ارسال کنید و مستقیماً در جدول قرار دهید.

اگر پیوند را باز کنید: pgjdbc/ubenchmsrk/InsertBatch.java، پس این کد در GitHub است. شما می توانید به طور خاص ببینید چه درخواست هایی در آنجا ایجاد می شوند. مهم نیست.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

راه اندازی کردیم. و اولین چیزی که متوجه شدیم این بود که استفاده نکردن از دسته به سادگی غیرممکن است. همه گزینه‌های دسته‌بندی صفر هستند، یعنی زمان اجرا در مقایسه با اجرای یک‌باره عملاً صفر است.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

داده ها را وارد می کنیم. این یک میز بسیار ساده است. سه ستون. و ما در اینجا چه می بینیم؟ می بینیم که هر سه این گزینه تقریباً قابل مقایسه هستند. و COPY البته بهتر است.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

این زمانی است که قطعات را وارد می کنیم. وقتی گفتیم که یک مقدار VALUES، دو مقدار VALUES، سه مقدار VALUES، یا 10 عدد از آنها را با کاما از هم جدا می کنیم. این الان فقط افقی است. 1، 2، 4، 128. مشاهده می شود که Batch Insert که به رنگ آبی کشیده شده است، حال او را بسیار بهتر می کند. یعنی وقتی یکی یکی را وارد می‌کنید یا حتی وقتی چهار را در یک زمان وارد می‌کنید، دو برابر بهتر می‌شود، صرفاً به این دلیل که کمی بیشتر در VALUES جمع شده‌ایم. عملیات EXECUTE کمتر.

استفاده از COPY در حجم های کوچک بسیار بی امید است. من حتی روی دو مورد اول نقاشی هم نکردم. به بهشت ​​می روند یعنی این اعداد سبز برای COPY.

وقتی حداقل صد ردیف داده دارید باید از COPY استفاده کنید. سربار باز کردن این اتصال زیاد است. و، صادقانه بگویم، من در این مسیر حفاری نکردم. من Batch را بهینه کردم، اما COPY را نه.

بعدش باید چیکار کنیم؟ ما آن را امتحان کردیم. ما می‌دانیم که باید از ساختارها یا یک حمام هوشمندانه استفاده کنیم که چندین معانی را با هم ترکیب کند.

PostgreSQL و JDBC تمام آب را می گیرند. ولادیمیر سیتنیکوف

چه چیزی را باید از گزارش امروز حذف کنید؟

  • PreparedStatement همه چیز ماست. این به بهره وری زیادی می دهد. یک فلاپ بزرگ در پماد ایجاد می کند.
  • و باید 6 بار EXPLAIN ANALYZE را انجام دهید.
  • و باید OFFSET 0 و ترفندهایی مانند +0 را رقیق کنیم تا درصد باقیمانده پرس و جوهای مشکل ساز خود را اصلاح کنیم.

منبع: www.habr.com

اضافه کردن نظر