چرا TimescaleDB انتخابی مناسب برای دادههای سری زمانی است ؟
بررسی معماری TimescaleDB در ذخیره و بازیابی موثر دادههای سری زمانی بر روی دیتابیس پستگرس
دادههای سری زمانی روز بروز نقش پررنگتری را در سامانههای اطلاعاتی ایفا میکنند و از نقشهای کلاسیکی مانند ذخیره لاگها و دادههای دریافتی از حسگرها، به ابزاری موثر در ذخیره دادههای تحلیلی و آماری تبدیل شدهاند (مانند بررسی رفتار کاربران در استفاده از سرویسهای یک اپ در بازههای زمانی مختلف و تولید گزارشات لحظهای مورد نیاز). در سالیان گذشته، برای استفاده موثر از این نوع دادهها، دیتابیسهای غیررابطهای مختلفی توسعه داده شده اند که InfluxDB
از معروفترین آنهاست اما وجود یک دیتابیس رابطهای کارآمد در این حوزه، به شدت احساس میشد. این نیاز باعث پاگرفتن دیتابیس TimeScaleDb به عنوان یک افزونه بر روی Postgres شد. در این مقاله که با کمک دوست عزیزم جناب علی رستمپور تهیه شده است، به معماری و نحوه مدیریت حجم بالای دادههای سریزمانی در این بانکاطلاعاتی رابطهای میپردازیم.
مقدمه
در سالهای اخیر شاهد افزایش ناگهانی حجم دادهها بوده ایم که عمدتا به دلیل بازارهای تلفیقی برای برنامه های IoT و یادگیری ماشین (دادههای تحلیلی و لاگها) بوده است. تخمین زده میشود که برای هر فرد زنده در این سیاره تا سال ۲۰۲۰ تقریباً ۱٫۷ مگابایت داده در هر دقیقه تولید می شود. بیشتر این داده ها در دریاچه های داده[۱] یا انبارهای داده ، به صورت خام یا تلخیص شده ذخیره می شوند. بخش بزرگی از این داده ها به عنوان داده های سری زمانی توسط IoT ، دستگاه ها و برنامههای نظارت یا برنامه های تلفن همراه تولید می شود.
دادههای سری زمانی
دادههای سری زمانی دادههایی هستند که هر رکورد آنها شامل زمان بوده، تحلیل و پردازش آنها به طور معمول وابسته به بازههای زمانی است.
از جمله این نوع دادهها میتوان به دادههای بورس، آبوهوا، توئیتها و حتی اخبار اشاره کرد.سریهای زمانی در تمامی حوزههای علوم کاربردی و مهندسی که زمان در آنها اندازهگیری و ذخیره میشود از سالیان دور حضور داشتهاند. بنابراین ، مکانیسم های ماندگاری دادهها برای سریهای زمانی از جمله کارهای قدیمی برای پایگاه دادهها هستند. بانکهای اطلاعاتی سری زمانی(TSDB)، نوع خاصی از پایگاههای داده هستند که برای ذخیره و پردازش بهینه دادههای سریزمانی (زمانمحور) ایجاد شدهاند.
اساس دادههای سری زمانی، اندازهگیریهای مکرر پارامترها در طول زمان است. اغلب اوقات، فواصل منظم هستند، اما این یک الزام نیست. هدف اصلی یک پایگاهداده سریهای زمانی، ذخیره یا ثبت داده های یک حسگر یا دادههای دیگر در طول زمان است. ذخیره سازی داده های سری زمانی هم می تواند توسط پایگاه داده های رابطه ای و هم توسط پایگاه داده های غیر رابطه ای انجام شود. هدف این مقاله هم بررسی تغییرات انجام گرفته در معماری پایگاه دادههای رابطه ای برای ذخیره موثر دادههای سری زمانی در پایگاه داده های رابطه ای است. همچنین نشان داده خواهد شد که با بازمعماری پایگاه داده های رابطه ای برای داده های سری زمانی، می توان از مزایای بسیار مهم پایگاه داده های رابطهای مانند پشتیبانی قوی از secondary Index
، زبان پرس و جوی غنی SQL
، پشتیبانی کامل از انواع Join ها و … بهره برد.
مثالی از کوئریهای موردنیاز برای دادههای سری زمانی را در زیر میتوانید مشاهده کنید. قالب آشنای SQL نیاز به توضیح را مرتفع میکند و خود کدها به حد کافی گویا هست (مزیت SQL در کار با دادههای سریزمانی) :
پایگاه داده های NoSQL یا رابطه ای؟
در سالهای اخیر، حجم دادههای سری زمانی به شدت توسعهیافته و نیاز به ابزارهایی برای مدیریت دادههای سری زمانی، در این مقیاس، بیش از پیش احساس میشود. تاکنون بیشتر ابزارهای تولید شده برای ذخیره و پردازش دادههای سری زمانی، مبتنی بر مدلهای دادهای NoSQL
بوده است.
واقعیت این است که دلیل اقبال افراد برای مدیریت دادههای سری زمانی به پایگاه داده های NoSQL
به بیشتر به بحث مقیاسپذیری آنها برمیگردد که به دلیل حجم بالای دادههای سری زمانی، یک الزام مهم است. از طرفی، پایگاه دادههای رابطهای ویژگی های بسیار مفیدی دارند که در بسیار از پایگاه داده های NoSQL
وجود ندارد یا به صورت ضعیف پشتیبانی می شود. از جمله این موارد میتوان به secondary Index
، زبان پرس و جوی غنی SQL، پشتیبانی کامل از انواع Join ها و … اشاره کرد. بنابراین اگر بتوان مشکل مقیاسپذیری دادهها را به نحوی حل کرد، می توان این ادعا را داشت که پایگاه داده های رابطهای می توانند گزینه بسیار مناسبی برای نگهداری داده های سری زمانی باشند.
چرا پایگاه داد های رابطه ای (معمولاً) مقیاس پذیری بالایی ندارند؟
مشکل عمومی مقایس پذیری پایگاه داده رابطهای به نحوه مدیریت ذخیره ، بازیابی و پردازش دادهها در آنها برمیگردد که این موضوع هم به دلیل استفاده گسترده از ایندکسها در ذخیره و بازیابی دادهها، به تفاوت چشمگیر مصالحه هزینه/ کارایی بین دیسک و حافظه بر میگردد. درست است که حافظه بسیار سریعتر از دیسک است ولی هزینه حافظه با توجه به ظرفیت آن بسیار بالاتر است.بنابراین این نکته مهم است که تمام مجموعه داده های ما در حافظه جای نمی گیرند، به همین دلیل لازم است که دادهها و ایندکسهای خود را روی دیسک بنویسیم.
در اکثر پایگاه داده های رابطه ای یک جدول به عنوان مجموعه ای از صفحات با طول ثابت از داده ( به عنوان مثال در PostgreSQL صفحات با سایز ۸KB ) ذخیره می شوند و در بالای آنها سیستم از یک ساختار دادهای مانند B-tree برای شاخص گذاری داده ها استفاده میکند. با استفاده از این ایندکس ها یک کوئری به صورت بسیار سریعتری می تواند یک سطر مشخص را بدون اینکه بخواهد کل یک جدول را بررسی کند پیدا کند. اگر دادههایی که با آنها کار میکنیم، حجم کمی داشته باشند که در نتیجه ایندکسهای آنها کوچک باشد، میتوان همه آنها را در حافظه نگه داشت. اما اگر دادهها زیاد باشند که در اغلب موارد اینگونه است، نمیتوان همه آنها را در حافظه نگه داشت و اینجاست که مشکل بعدی پیش میآید : درگیری بیش از حد دیسک و کاهش شدید سرعت کار با دادهها.
به روزرسانی یک قسمت تصادفی از درخت شاخص می تواند disk I/O
قابل توجهی را درگیر کند، زیرا صفحات از دیسک به حافظه خوانده شده، اصلاح و بر روی دیسک بازنویسی میشوند. برای این منظور، یک پایگاه داده رابطه ای مانند PostgreSQL
یک B-tree
را برای هر index نگه می دارد، تا مقادیر موجود در ایندکس به طور موثری دستیابی شوند و عملیات مدیریت دادهها با سریعترین حالت ممکن صورت گیرد. مشکل زمانی به وجود می آید که ستونهای زیادی ایندکس شوند (به ازای هر ستونی که زیاد با آن سروکار داریم و سرعت بازیابی اطلاعات بر اساس آن ستون برای ما مهم است، از ایندکسها استفاده میکنیم). با این توصیف، چون پایگاه داده فقط دسترسی به دیسک در محدوده page-sized را دارد، ممکن است با یک به روز رسانی کوچک، به دلیل وجود ایندکسهای زیاد بر روی یک رکورد، Swap و تبادل زیادی بین حافظه و دیسک اتفاق بیفتد. هزینه این Swap می تواند در گراف کارایی شکل زیر که مربوط به PostgreSQL
است دیده شود. جایی که بهرهوری درج، با توجه به افزایش اندازه جداول (تقریبا بعد از اندازه ۵۰M ) با شیب نسبتا تندی کاهش پیدا می کند. حافظه مورد استفاده برای این تست کارایی از نوع SSD
بوده و تعداد کاربران ۱۰ نفر که هرکدام سطرهای مختلفی را درج می کردند.
ملاحظات کارایی پایگاه دادههای NoSQL
مشکل اصلی مقیاسپذیری پایگاههای دادههای رابطهای را بررسی کردیم که به دلیل وجود ایندکسها در این نوع دیتابیسها و درگیر شدن زیاد دیسک بخاطر نرخ بالای تغییرات همزمان بود که به دلیل نوع ایندکس انتخاب شده (B+Tree) ناگزیر مینمود. برای حل این مشکل، تعداد زیادی از پایگاه داده های NoSQL
از ساختار دیگری برای ایندکس کردن دادهها استفاده میکنند که با نام Log-structured merge (LSM) trees شناخته میشود. این ساختار در شکل زیر نشان داده شده است.
در این ساختار، همه آپدیت ها ابتدا در یک جدول مرتب شده در درون حافظه نوشته می شوند و سپس به صورت دسته ای از داده های مرتب و تغییر ناپذیر بر روی دیسک نوشته می شوند. یعنی همه نوشتن ها در یک درخت LSM در یک جدول مرتب شده در حافظه انجام می شوند که وقتی به یک اندازه مناسب رسیدند (به عنوان ” sorted string table” یا SSTable) به عنوان یک فایل داده تغییرناپذیر به دیسک منتقل می شوند. این فایلهای مرتب شده یا همان SSTable ها، در بازههای زمانی منظم با هم ادغام شده و یک SSTable بزرگتر را میسازند و اگر چندین تغییر بر روی یک رکورد انجام شده باشد، فقط آخرین تغییر در این فایل جدید باقی مانده، بقیه حذف میشود. این جداول هم به تدریج با دادههای موجود در دیتابیس ادغام و دیتابیس، آپدیت میشود. هنگام جستجو و بازیابی اطلاعات، دادههای موجود در دیتابیس با دادههای موجود در این فایلهای مرتب، مقایسه شده و همواره جدیدترین نسخه، به کاربر نشان داده میشود. این روش، هر چند هزینههای بازیابی اطلاعات را افزایش میدهد اما هزینه تغییرات و نوشتنهای متوالی را به شدت، کاهش می دهد.
معماری بیان شده در بالا در اکثر پایگاه داده های NoSQL مانند LevelDB, Google BigTable, Cassandra, MongoDB
(WiredTiger), and InfluxDB
استفاده شده است و به نظر ساختار مناسبی می آید ولی چند چالش در مورد آن وجود دارد:
- نیاز به حافظه زیاد (برخلاف یک B-Tree، در یک درخت
LSM
هیچ ترتیب منحصر بفردی وجود ندارد و همچنین هیچ ایندکس سراسری برای بر روی همه کلیدهای موجود درSSTable
ها وجود ندارد و این کار پیدا کردن یک کلید خاص را بسیار پیچیده می کند.برای رفع این مورد می توان ایندکسهای تمامSSTable
ها را به طور کامل در حافظه قرار داد که این مساله مقدار حافظه مورد نیاز را افزایش می دهد). - پشتیبانی ضعیف از Secondary Index (با توجه به اینکه آنها هیچ نظم و ترتیب سراسری ندارند، درختان LSM به طور طبیعی از شاخص های ثانویه پشتیبانی نمی کنند).
- فقدان Join
- از دست دادن اکو سیستم SQL ( جامعه جهانی بسیار وسیعی از
SQL
استفاده می کنند). - عدم کارآیی برای دستورات جستجوی بازه ای : با توجه به ساختار key-Value، کوئری های که به صورت range هستند، به صورت بهینه پاسخ داده نمیشوند.
آیا راه حل بهتری برای مدیریت داده های سری زمانی وجود دارد؟ برای فهم این موضوع نیاز به شناخت دقیق تر دادههای سری زمانی داریم.
داده های سری زمانی متفاوت هستند!
مشکل اصلی در رابطه با پایگاه داده های سری زمانی از جایی شروع شد که شرکت IBM
در سال ۱۹۷۰، Seminal System R را راه انداخت و از پایگاه داده های رابطه ای برای پردازش تراکنش های آنلاین (OLTP
) استفاده شد.
در OLTP عملیات عمدتا از جنس تراکنش های آپدیت بود که سطرهای مختلفی از پایگاه داده را تغییر می داد. برای مثال به یک ترانش انتقال وجه بانک توجه کنید که در آن پولی از یک حساب برداشت شده و به حساب شخص دیگری واریز می شود. در این انتقال، دو سطر و احتمالاً دو فیلد از هر سطر، آپدیت میشود.
در داده های سری زمانی ، با جریان پیوستهای از دادهها و یا اندازهگیریها (در مورد حسگرها) مواجه هستیم که در همه آنها، عملیات اصلی مورد نیاز، اضافه کردن “اطلاعات جدید” به پایگاهداده به صورت پیوسته است. البته این امکان وجود دارد که اطلاعات بسیار دیرتر از زمانی برسد که تولید شده یا برچسب زمانی خورده و یا به علت تاخیر شبکه / سیستم یا به دلیل اصلاحات برای به روز رسانی دادههای موجود، این امر نوعاً استثنا است، نه یک قاعده ثابت.
بنابراین بین نوع عملیات مورد نیاز سیستمهای تراکنش محور و سری زمانی، تفاوتهای ماهوی را شاهد هستیم.
در OLTP یا دادههای تراکنش محور :
- آپدیت در درجه اول اهمیت قرار دارد یعنی باید بتوان با سرعت و کارآیی مناسب، داده ها را اصلاح کرد.
- نوشتنها به صورت تصادفی توزیع شده هستند و نمیتوان پیشبینی کرد نوشتن بعدی، قرار است بر روی کدام داده انجام شود.
- اغلب تراکنش ها شامل چندین جدول مختلف میشوند یعنی باید چندین کلید اصلی را جستجو و دادههای آنها را بازیابی کرد.
در دادههای سری زمانی:
Insert
ها در درجه اول اهمیت هستند.- نوشتن ها تصادفی نیست و در بازه زمانی اخیر انجام می شود. (زمانمند هستند و به ترتیب زمانی وارد میشوند)
- کلید اصلی اغلب یک
TimeStamp
است و ممکن است علاوه برTimeStamp
موارد دیگری نیز چون ServerID، ِDeviceID و … همراه باTimeStamp
باشد.
راه حل پایگاه دادههای رابطهای برای پردازش سری زمانی
در شکل زیر راه حل استاندارد اولیه پایگاه داده های رابطه ای برای پردازش جریان داده ای و ایده نوین اَبَرجدول در TimescaleDB
دیده می شود. در راه حل اولیه که همان استفاده از ایندکسهای B+است، بخشی از نودهای میانی، در حافظه نگهداری میشوند تا فرآیند جستجو و بازیابی اطلاعات سرعت مناسب داشته باشد اما در رهیافت جدید TimescaleDB
، دادهها به بخشها یا Chunk
هایی تقسیم و ذخیره میشوند و همواره آخرین بخشها در حافظه نگهداری میشود. کاربران از طریق اَبَرجدولها به این بخشها دسترسی خواهند داشت.
به عبارت دقیقتر، در پایگاه داده TimescaleDB
که قصد دارد از پایگاهداده رابطهای پستگرس برای ذخیره دادههای سری زمانی به نحو موثر استفاده کند، از مفهوم Hyper table و Chunk استفاده می شود. یک جدول مجازی یا اَبَرجدول، در واقع یک تجرید یا یک دید مجازی از همه جداول منفردی است که داده ها را در خود جای داده اند. این جداول منفرد تشکیل دهنده یک اَبَرجدول، chunk نامیده می شوند.
هر Chunk
در یک جدول پایگاه داده داخلی (به عنوان یک جدول معمولی) ذخیره میشود، بنابراین ایندکس ها فقط با اندازه هر Chunk
رشد می کنند و نه به اندازه کل. در HyperTable
از آنجا که دادهها معمولاً در یک بازه محدود (چند ثانیه قبل یا بعد از زمان جاری سیستم بسته به تاخیر یا عدم تنظیم بودن ساعت دستگاهها) وارد میشوند، میتوان همواره آخرین Chunk
را در حافظه نگه داشت. با اینکار از یک Swap پرهزینه به دیسک جلوگیری می شود.
Adaptive Time/Space Chunking
ایده اصلی مقیاسپذیری و روش مدیریت دادهها در TimescaleDB
را مشاهده کردید. در این بخش، به راه حل نهایی و معماری TimescaleDB
میپردازیم. راه حل های قبلی که مطرح شد، تلاش می کردند که از نوشتن های کوچک بر روی دیسک حذر کنند. آنها تلاش می کردند که مشکل OLTP
را که مسئله Update در محلهای تصادفی بود را حل کنند. اما مساله داده های سری زمانی متفاوت است: در اینجا چیزی که بسیار مهم است درج است نه ویرایش. Insert همواره در بازه زمانی اخیر انجام می شود و برخلاف OLTP
که به روز رسانی دادهها معمولاً در مکانهای تصادفی صورت میگیرد، می توان گفت که Workload داده های سری زمانی به صورت append only
است.
این ویژگی داده های سری زمانی بسیار مهم و جالب توجه است، به این معنی که اگر داده ها با توجه به زمان مرتب شوند، ما همیشه نوشتن را در آخر دیتاستی که داریم انجام می دهیم. سازماندهی داده ها توسط زمان همچنین این اجازه را به ما می دهد که مجموعه کاری واقعی صفحات پایگاه داده را کوچک نگه داریم که بتوانیم آنها را در حافظه جای دهیم. و در مورد Read ، که ما زمان کمتری را برای بحث در مورد آن صرف کرده ایم ، می تواند از این مزیت بهره ببرد: اگر بسیاری از پرس و جوهای خوانده شده مربوط به بازه زمانی اخیر (مثلاً برای داشبوردهای لحظهای) باشد ، آنگاه این داده ها از قبل در حافظه، Cache میشوند.
در نگاه اول ممکن است به نظر برسد که این کار شبیه ایندکس گذاری بر روی Time است که به ما قابلیت نوشتن و خواندن کارا را می دهد. اما هنگامی که ما می خواهیم از ایندکس دیگری مانند ServerID
یا DeviceID
و یا هر کلید اصلی دیگری به عنوان Secondary Index
داشته باشیم، متوجه می شویم که این روش مناسب نبوده و ما را به درج به صورت تصادفی در درخت B-tree
برای استفاده از ایندکس دوم مجبور می کند.
برای حل این مشکل، میتوان از ایندکس گذاری سلسله مراتبی استفاده کرد. دو حالت مختلف این ایندکس گذاری سلسله مراتبی را در شکل زیر میتوانید مشاهده کنید:
اما میتوان برای مدیریت موثر زمان و سایر دادهها، (بُعد زمان و بُعد مکان/وسیله/کاربر و ….) از روش دیگری هم استفاده کرد که روش بخشبندی تطبیقی زمان/مکان adaptive time/space chunking نامیده میشود و در TimescaleDB
استفاده شده است.
در این روش به جای ایندکس سازی بر اساس زمان و یا ایندکس دوم مورد نیاز بر روی دادهها، Cunking
یا بخشبندی داده ها به صورت همزمان بر حسب دو بعد بازه زمانی و کلید اصلی ساخته می شود (کلید اصلی برای نمونه می تواند ServerID
و یا هر چیز دیگری باشد). برای تمایز ایجاد کردن از Partition
ها، ما به Chunk
های اشاره می کنیم که به طور معمول با تقسیم فضای اصلی کلید تعریف می شوند.
در روش بخشبندی تطبیقی، دادهها به چانکهایی با محوریت زمان تقسیم شده و در هر چانک یا بخش، دادهها بر اساس کلید دوم، مرتب شدهاند که این موضوع باعث میشود که بتوان یک اندیس سراسری بر اساس کلید دوم هم تعریف کرد و همزمان هم بر اساس زمان بتوان به دادهها دسترسی داشت و هم بر اساس، مکان (یا هر کلید دیگری) .
با این روش، دادههای ورودی به صورت مفهومی هنگام درج در دیتابیس، در مکان مناسب از یک چانک یا بخش قرار میگیرند.
مزایای Chunking
از آنجا که هریک از این chunk
ها به صورت جدولهایی در پایگاه داده ذخیره می شوند، و Query Planner
از محدوده chunk
ها آگاه است (اندیس زمان و مکان)، Query Planner
می تواند به سرعت تعیین کند که کدام داده عملیاتی متعلق به کدام chunk است. این موضوع می تواند هم برای درج سطرها، وهم برای انتخاب مجموعه ای از chunk
ها که برای اجرای کوئری مورد نیاز است، استفاده شود.
ویژگی بسیار خوب این روش این است که همه ایندکس های ما بر رو chunk
ها که کوچکتر هستند ساخته می شوند نه بر روی جدول ها که کل دیتاست را نمایش می دهند. بنابراین اگر ما سایز chunkها را به طور مناسبی انتخاب کنیم، می توانیم آخرین جدول به همراه درخت های B-trree
آن را به طور کامل در حافظه قرار دهیم و از swap
کردن به دیسک جلوگیری کنیم، در حالی که از ویژگی پیشتیبانی از چند ایندکس نیز بهره بردهایم.
از دیگر مزایای chunking
می توان به به این مورد اشاره کرده که با استفاده از chunkها می توان بر روی یک نود با اضافه کردن دیسک، Scale Up داشت یعنی بدون نیاز به افزودن نودی دیگر در شبکه، با افزودن تعداد دیسکهای یک سیستم، امکان توزیع خودکار چانکها در بین دیسکها را توسط خود دیتابیس فراهم کرد. با استفاده از این تکنیک سرعت Insert افزایش پیدا می کند و امکان کوئری گرفتن موازی وجود دارد.
علاوه بر اینکه می توان بر روی یک نود Scale up داشت، می توان با استفاده از چندین سرور به صورت توزیع شده Scale Out نیز داشت. به این صورت که chunk ها بر روی سرور های مختلف توزیع می شوند.
روش پیاده سازی Chunking
chunkها نقش اصلی را در معماری TimescaleDB
ایفا میکنند و بنابراین مدیریت درست آنها، تاثیر زیادی روی کارآیی این دیتابیس خواهد داشت.
برای پیادهسازی چانکها سه روش اصلی داریم که هنگام طراحی جداول در TimescaleDB
قابل تنظیم است :
- بازه زمانی ثابت : در این روش، بسته به نوع و حجم دادهها، بازه زمانی را معیار ایجاد چانکها تعریف میکنیم. مثلاً بازه یک روزه، باعث میشود تمام دادههای یک روز درون یک چانک قرار بگیرند و با شروع روز جدید، یک چانک (یک جدول داخلی جدید) ایجاد شود.مشکل این روش این است که اگر حجم داده های روزانه به تدریج زیاد شود و مثلا داده های یک روز از حد مطلوبی که در نظرگرفته بودیم تجاوز کند، با کاهش کارآیی مواجه خواهیم شد.
- اندازه چانک ثابت : در این روش، حجم ثابتی برای جداول داخلی یعنی چانکها در نظر میگیریم . مثلا فرض کنید ۱ گیگابایت را به عنوان اندازه یک چانک تعیین میکنیم. با رسیدن حجم دادهها در یک چانک به این سقف، چانک فعلی بسته شده، بازه زمانی ابتدا و انتهای آن ذخیره شده(برای ایندکس گذاری و جستجوهای بعدی ) و چانک جدید ایجاد میشود. مشکل این روش هم این است که دادههایی که با تاخیر میرسند، چون در بازه زمانی یک چانک بسته شده قرار میگیرند، باید به دادههای آن اضافه شوند. این موضوع ، باعث افزایش حجم ناخواسته چانکها میشود که بسته به کاربرد، ممکن است حجم افزوده شده چندان قابل اعتنا نباشد و یا برعکس، مشکلاتی در کارآیی سیستم ایجاد کند.
- بازههای زمانی تطبیق شونده : راه حل سوم که رهیافتی مابین دو روش قبلی است، تعیین بازه زمانی و حداکثر داده مجاز قابل ذخیره در یک چانک است. چانکها بر اساس بازه زمانی تعیین شده ایجاد می شوند اما اگر از سقف مشخص شده عبور کنند، درون آن بازه زمانی، چانک جدیدی ایجاد خواهد شد. این موضوع تضمین می کند همیشه آخرین چانک با اندازه تعیین شده تطابق دارد و قابل نگهداری در حافظه است.
انتخاب روش مناسب، به شما و نیازمندیهایتان بستگی دارد.
بررسی سریع یک مثال کاربردی
برای اینکه یک دید عملی و کاربردی نسبت به TimescaleDB
پیدا کنید و نحوه طراحی و کوئری گرفتن اطلاعات را در یک نگاه ببینید مثالی از ذخیره داده های ترافیک را با هم مرور میکنیم. فرض کنید قرار است به صورت روزانه اطلاعات دوربینهای نظارتی درون شهری را ذخیره کنید. از آنجا که دادهها ماهیت زمانمحور دارند و کوئریهای مورد نیاز اغلب در بازههای زمانی صورت میگیرند، این بخش از دادهها را درون پستگرس، با افزونه TimescaleDB
مدیریت می کنیم . جدول vehicle_Traffc
را به صورت زیر درون پستگرس ایجاد میکنیم :
سپس اَبَرجدول متناظر را در TimescaleDB
میسازیم :
همانطور که مشاهده میکنید، بازه زمانی هر چانک را یک روز تعیین کردهایم. در مرحله بعد، با همان دستورات معمول SQL
به درج داده در جدول vehicle_traffic
میپردازیم . بعد از ورود حجم داده مناسب(مثلاً برای چند روز مختلف) اگر از دستور Explain
استفاده کنیم تا ببینیم پشت صحنه، کوئری به چه صورت پاسخ داده میشود، میبینیم که دادهها از چندین چانک مختلف بازیابی میشوند :
نمونهای از کوئریهایی که میتوانیم روی این دادهها داشته باشیم را در ادامه مشاهده میکنید :
همانطور که میبینید، sql
در تمام این مراحل، حرف اول را میزند که نکته بسیار مهمی در به کارگیری عملی دادههای سری زمانی در دنیای واقعی است.
کارایی روش ارائه شده نسبت به روش سنتی درPostgerSQL
استفاده از بهینهسازی هایی که در بالا بدانها اشاره شد، باعث شده است انتخاب TimescaleDB
در مقایسه با پستگرس برای دادههای سری زمانی به یک اصل واضح تبدیل شود. نمودارهای زیر این موضوع را نشان میدهند.(منبع)
همانطور که قابل مشاهده است TimescaleDB
با توجه به بالا رفتن حجم داده، نرخ Insert
تقریبا ثابتی دارد و کارایی Insert
کاهش چندانی پیدا نمی کند و می توان گفت که تقریبا مستقل از سایز دیتاست است. در کوئریهای پیچیده هم TimescaleDB
به وضوح، برتری خود را نشان داده است:
سایر مقایسهها و نمودارها را در این آدرس میتوانید مشاهده کنید.
سال گذشته مقالهای خواندم که در آن TimescaleDB
و کاساندرا برای ذخیره و بازیابی دادههای سری زمانی مقایسه شده بودند که در آن، TimescaleDB
با پنج نود، کاساندرا با ۳۰ نورد را با اختلاف زیاد پشت سر گذاشته بود (البته برای دادههای سری زمانی و برای دادههایی که با دیتامدل سطر گسترده کاساندرا مطابق هستند این مساله صدق نمیکند)
نتیجه گیری
همانطور که دیدیم باز طراحی پایگاه داده رابطهای پستگرس برای ذخیره دادههای سری زمانی، باعث شده است هم از مزایای SQL
برای این نوع دادهها استفاده کنیم و هم کارآیی بالا و مقیاسپذیری مناسبی داشته باشیم. هر چند TimescaleDB
هنوز در ابتدای راه توسعه و محبوبیت خود است اما همراهی آن با پستگرس، نویدبخش آیندهای روشن برای این دیتابیس تخصصی در حوزه دادههای سری زمانی است.
[۱] Data lakes
خیلی جامع، عالی و روان بود.
ممنونم
بسیار جامع و عالی. سپاس از شما