في كل مرة تبدأ فيها محادثة حول استخدام قواعد بيانات مختلفة كمصدر للبيانات ، يظهر موضوع معرفات السجل أو الكائنات أو أي شيء آخر. في بعض الأحيان ، يمكن أن ينظر المشاركون في تنسيق بروتوكول التبادل لعدة أشهر. int
- bigint
- guid
، ثم في دائرة. بالنسبة إلى مهام وحدة التخزين ، مع الأخذ في الاعتبار أنه لا يوجد في الأصل دعم R كبير (السعة ~ 2 ^ 64) ، يمكن أن يكون اختيار العرض الصحيح لمثل هذه المعرفات حاسماً من حيث الأداء. هل هناك حل واضح وعالمي؟ فيما يلي بعض الاعتبارات العملية التي يمكن استخدامها في المشاريع كاختبار عبث.
كقاعدة عامة ، سيتم استخدام المعرفات لثلاث فئات من المهام:
بناءً على ذلك ، سنقوم بتقييم الأساليب المختلفة.
إنه استمرار للمنشورات السابقة .
تخزين string
خيار البيانات الصغيرة جيد جدا. هنا والقدرة على التقاط أي طول للمعرف ، والقدرة على دعم ليس فقط معرفات رقمية ، ولكن أيضًا معرفات أبجدية رقمية. ميزة إضافية هي القدرة المضمونة على تلقي البيانات بشكل صحيح من خلال أي بروتوكول قاعدة بيانات غير أصلية ، على سبيل المثال ، من خلال واجهة برمجة تطبيقات REST الخاصة بالبوابة.
سلبيات واضحة أيضا. ارتفاع استهلاك الذاكرة ، زيادة حجم المعلومات من قاعدة البيانات ، تدهور الأداء على مستوى الشبكة والمستوى الحسابي.
نحن نستخدم حزمة bit64
قد يظن الكثير ممن سمعوا اسم هذه الحزمة فقط أنه الحل الأمثل. للأسف ، هذا ليس صحيحًا تمامًا. هذه ليست وظيفة إضافية فقط أعلى (اقتباس: " مرة أخرى ، يكون الخيار واضحًا: يحتوي R على نوع بيانات 64 بت واحد فقط: الزوجي. باستخدام الزوجي ،
يرث integer64 بعض الوظائف مثل is.atomic ، الطول ، الطول <- ، الأسماء ، الأسماء <- ، باهتة ، خافتة <- ، خافتة ، أسماء خافتة. ' ) ، لذلك لا يزال هناك توسع هائل في الحساب الأساسي وليس هناك ضمانات بأنه لن ينفجر في أي مكان ولن يكون هناك تعارض مع الحزم الأخرى.
نحن نستخدم نوع numeric
هذه خدعة صحيحة تمامًا ، وهي حل وسط جيد لأولئك الذين يعرفون ما الذي سيتم إخفاؤه بالضبط في استجابة int64
من قاعدة البيانات. بعد كل شيء ، ليس كل 64 بت حقا سوف تشارك هناك. في كثير من الأحيان قد يكون هناك عدد أقل بكثير من 2 ^ 64.
مثل هذا الحل ممكن بسبب تفاصيل تنسيق الفاصلة العائمة المزدوجة الدقة. يمكن العثور على التفاصيل في مقالة تنسيق الفاصلة العائمة ذات الدقة المزدوجة الشائعة.
The 53-bit significand precision gives from 15 to 17 significant decimal digits precision (2−53 ≈ 1.11 × 10−16). If a decimal string with at most 15 significant digits is converted to IEEE 754 double-precision representation, and then converted back to a decimal string with the same number of digits, the final result should match the original string. If an IEEE 754 double-precision number is converted to a decimal string with at least 17 significant digits, and then converted back to double-precision representation, the final result must match the original number.
إذا كان لديك 15 رقمًا عشريًا أو أقل في المعرف ، فيمكنك استخدام الأرقام numeric
وليس القلق.
نفس الخدعة جيدة عندما تحتاج إلى العمل مع البيانات المؤقتة ، خاصة تلك التي تحتوي على مللي ثانية. يستغرق نقل البيانات المؤقتة عبر الشبكة في نموذج نصي وقتًا ، بالإضافة إلى ذلك ، في الجانب المتلقي ، تحتاج إلى تشغيل محلل النص -> POSIXct
، وهو أيضًا POSIXct
من الموارد (انخفاض الأداء في بعض الأحيان). نقل في شكل ثنائي ليس حقيقة أن جميع السائقين سيدعم نقل المنطقة الزمنية وملي ثانية. لكن نقل الوقت بدقة إلى مللي ثانية في منطقة UTC في تمثيل الطابع الزمني لليونيكس (13 منزلاً عشريًا) جيد جدًا وبلا ضياع بواسطة التنسيق numeric
.
ليس بهذه البساطة والوضوح
إذا ألقينا نظرة فاحصة على الإصدار بالخطوط ، فإن وضوح البيان الأولي وفئته يتراجعان قليلاً. العمل مع الأوتار في R ليس بالأمر السهل ، حتى يتم حذف الفروق الدقيقة في محاذاة كتل الذاكرة والإعداد المسبق. إذا حكمنا من خلال الكتب والوثائق المتعمقة ، لا يتم تخزين متغيرات السلسلة في حد ذاتها في متغير ، ولكن يتم وضعها في تجمع سلاسل عام. كل الخطوط. ويستخدم هذا التجمع بواسطة صفائف السلسلة لتقليل استهلاك الذاكرة. أي سيكون متجه النص عبارة عن مجموعة من الأسطر في التجمع العمومي + ناقل للارتباطات بسجلات من هذا التجمع.
library(tidyverse) library(magrittr) library(stringi) library(gmp) library(profvis) library(pryr) library(rTRNG) set.seed(46572) RcppParallel::setThreadOptions(numThreads = parallel::detectCores() - 1)
نرى أنه حتى بدون الانتقال إلى مستوى C ++ ، فإن الفرضية ليست بعيدة عن الحقيقة. يتزامن حجم متجه السلسلة تقريبًا مع حجم مؤشرات 64 بت ، ويشغل المتغير نفسه مساحة أقل بكثير من الملف الموجود على القرص.
File size: 62M. Constructed from file object's (m2) size: 7.65M. Pure pointer's size: 7.63M
ومحتوى المتجهات قبل الكتابة وبعد القراءة متطابق. تشير العناصر المتجهة إلى نفس كتل الذاكرة.
لذا فإن نظرة فاحصة على استخدام سلاسل النص كمعرفات لم تعد فكرة مجنونة. dplyr
data.table
التجميع والتصفية والدمج ، باستخدام dplyr
و data.table
قراءات متشابهة تقريبًا data.table
character
، مما يوفر تأكيدًا إضافيًا للتحسين نظرًا للتجمع الشامل. بعد كل شيء ، يجري العمل مع مؤشرات حجمها إما 32 أو 64 بت ، وهذا يتوقف على التجميع R (32/64) ، وهذا هو بالضبط النوع numeric
.
بالمناسبة ، يمكن عرض الحد الأقصى لحجم ذاكرة R المتاحة باستخدام الأمر fs::fs_bytes(memory.limit())
.
لكي نكون صادقين ، تجدر الإشارة إلى أن dplyr
لم يكن لديه دائمًا dplyr
سريع في dplyr
، راجع الحالة "الانضمام بواسطة عمود حرف بطيء ، مقارنةً بالانضمام إلى عمود عامل. # 1386 {مغلق}" . يقترح مؤشر الترابط هذا استخدام إمكانيات تجمع السلاسل العامة ومقارنة ليس السلاسل على هذا النحو ، ولكن يشير إلى السلاسل.
تفاصيل إدارة الذاكرة
المصادر الأساسية
استنتاج
بطبيعة الحال ، يتم طرح هذا السؤال باستمرار بشكل أو بآخر ، وعدد من الروابط أدناه.
ولكن من أجل فهم ما يجب فعله بوعي ، وما هي الفرص والقيود ، من الأفضل النزول إلى أدنى مستوى ممكن. كما اتضح ، هناك كتلة من التفاصيل غير الواضحة. هذا المنشور ذو طبيعة بحثية ، لأنه يؤثر على الجوانب الأساسية تمامًا لـ R ، والتي يستخدمها القليل من الناس في عملهم اليومي. إذا كانت هناك إضافات أو تعليقات أو تصحيحات مهمة ، فسيكون من الممتع للغاية التعرف عليها.
المنشور السابق هو "استخدام R للمهام المساعدة" .