SELECT مرة واحدة فقط، ثم تقديم عمليات التنفيذ اللاحقة للاستعلام نفسه مباشرةً من ذاكرة التخزين المؤقت.
واعتمادًا على نوع الاستعلامات، يمكن أن يؤدي ذلك إلى تقليل زمن الوصول واستهلاك الموارد على ClickHouse server بشكل كبير.
الخلفية والتصميم والقيود
- في ذاكرات التخزين المؤقت المتسقة من ناحية المعاملات، تُبطِل قاعدة البيانات (تستبعد) نتائج الاستعلامات المخزنة مؤقتًا إذا تغيّرت نتيجة استعلام
SELECTأو كان من المحتمل أن تتغيّر. في ClickHouse، تشمل العمليات التي تغيّر البيانات عمليات insert/update/delete في الجداول أو عمليات الدمج من نوع collapsing. ويُعدّ التخزين المؤقت المتسق من ناحية المعاملات مناسبًا بشكل خاص لقواعد بيانات OLTP، مثل MySQL (الذي أزال ذاكرة التخزين المؤقت للاستعلامات بعد v8.0) و Oracle. - في ذاكرات التخزين المؤقت غير المتسقة من ناحية المعاملات، يُقبل وجود فروق طفيفة في نتائج الاستعلامات على افتراض أن جميع عناصر cache
تُمنح فترة صلاحية تنتهي بعدها (مثلًا دقيقة واحدة)، وأن البيانات الأساسية لا تتغير إلا بقدر محدود خلال هذه الفترة.
ويُعد هذا النهج، عمومًا، أنسب لقواعد بيانات OLAP. وكمثال على حالة يكون فيها التخزين المؤقت غير المتسق من ناحية المعاملات كافيًا،
تخيّل تقرير مبيعات بالساعة في أداة لإعداد التقارير يصل إليه عدة مستخدمين في الوقت نفسه. فعادةً ما تتغير بيانات المبيعات
ببطء يكفي لأن تحتاج قاعدة البيانات إلى compute التقرير مرة واحدة فقط (ويمثل ذلك أول استعلام
SELECT). وبعد ذلك يمكن تقديم الاستعلامات اللاحقة مباشرةً من ذاكرة التخزين المؤقت للاستعلامات. وفي هذا المثال، قد تكون فترة صلاحية معقولة 30 دقيقة.
إعدادات التكوين والاستخدام
في ClickHouse Cloud، يجب استخدام إعدادات على مستوى الاستعلام لتعديل إعدادات ذاكرة التخزين المؤقت للاستعلامات. لا تتوفر حاليًا إمكانية تعديل إعدادات على مستوى config.
يشغّل clickhouse-local استعلامًا واحدًا فقط في كل مرة. ونظرًا إلى أن تخزين نتيجة الاستعلام مؤقتًا لا يكون ذا جدوى، فإن
ذاكرة التخزين المؤقت لنتيجة الاستعلام تكون معطّلة في clickhouse-local.
use_query_cache = true) النتيجة المحسوبة من ذاكرة التخزين المؤقت وتُعيدها فورًا.
لا تسري
use_query_cache وجميع الإعدادات الأخرى المرتبطة بذاكرة التخزين المؤقت للاستعلامات إلا على عبارات SELECT المستقلة. وعلى وجه الخصوص،
لا تُخزَّن نتائج عبارات SELECT الموجَّهة إلى العروض المُنشأة باستخدام CREATE VIEW AS SELECT [...] SETTINGS use_query_cache = true في ذاكرة التخزين المؤقت ما لم تُنفَّذ عبارة SELECT
مع SETTINGS use_query_cache = true.true افتراضيًا). يتحكم الإعداد الأول
في ما إذا كانت نتائج الاستعلامات ستُخزَّن في ذاكرة التخزين المؤقت، بينما يحدد الإعداد الثاني ما إذا كان ينبغي على قاعدة البيانات محاولة استرجاع نتائج الاستعلامات
من ذاكرة التخزين المؤقت. على سبيل المثال، سيستخدم الاستعلام التالي ذاكرة التخزين المؤقت بشكل سلبي فقط، أي سيحاول القراءة منها دون تخزين
نتيجته فيها:
use_query_cache وenable_writes_to_query_cache و
enable_reads_from_query_cache فقط مع استعلامات محددة. ويمكن أيضًا تمكين التخزين المؤقت على مستوى المستخدم أو الملف الشخصي (مثلًا عبر SET use_query_cache = true)، لكن ينبغي الانتباه إلى أن جميع استعلامات SELECT قد تُرجع عندئذٍ نتائج مخزنة مؤقتًا.
يمكن مسح ذاكرة التخزين المؤقت للاستعلامات باستخدام التعليمة SYSTEM CLEAR QUERY CACHE. ويُعرض محتوى ذاكرة التخزين المؤقت للاستعلامات في جدول النظام
system.query_cache. ويظهر عدد مرات الإصابة والإخفاق في ذاكرة التخزين المؤقت للاستعلامات منذ بدء تشغيل قاعدة البيانات كحدثين
“QueryCacheHits” و”QueryCacheMisses” في جدول النظام system.events. ولا يُحدَّث هذان العدادان إلا من أجل
استعلامات SELECT التي تعمل مع الإعداد use_query_cache = true، أما الاستعلامات الأخرى فلا تؤثر في “QueryCacheMisses”. ويُظهر الحقل query_cache_usage
في جدول النظام system.query_log لكل استعلام مُنفَّذ ما إذا كانت نتيجة الاستعلام قد كُتبت إلى
ذاكرة التخزين المؤقت للاستعلامات أو قُرئت منها. وتُظهر المقاييس QueryCacheEntries وQueryCacheBytes في جدول النظام
system.metrics عدد الإدخالات / البايتات التي تحتوي عليها ذاكرة التخزين المؤقت للاستعلامات حاليًا.
توجد ذاكرة التخزين المؤقت للاستعلامات مرة واحدة لكل عملية خادم ClickHouse. ومع ذلك، لا تكون النتائج المخزنة مؤقتًا مشتركة بين المستخدمين افتراضيًا. ويمكن
تغيير ذلك (انظر أدناه)، لكن لا يُنصح به لأسباب أمنية.
تُشار نتائج الاستعلامات في ذاكرة التخزين المؤقت للاستعلامات بواسطة شجرة البنية المجردة (AST) الخاصة
باستعلاماتها. وهذا يعني أن التخزين المؤقت لا يتأثر بالأحرف الكبيرة أو الصغيرة، فعلى سبيل المثال يُعامَل SELECT 1 وselect 1 على أنهما الاستعلام نفسه. ولجعل
المطابقة أكثر طبيعية، تُزال من AST جميع الإعدادات على مستوى الاستعلام المتعلقة بذاكرة التخزين المؤقت للاستعلامات وتنسيق المخرجات)
.
إذا أُجهض الاستعلام بسبب استثناء أو إلغاء من المستخدم، فلن يُكتَب أي إدخال في ذاكرة التخزين المؤقت للاستعلامات.
يمكن تهيئة حجم ذاكرة التخزين المؤقت للاستعلامات بالبايتات، والحد الأقصى لعدد إدخالات التخزين المؤقت، والحد الأقصى لحجم كل إدخال من إدخالات التخزين المؤقت (بالبايتات وبالسجلات)
باستخدام خيارات مختلفة من خيارات تهيئة الخادم.
users.xml، ثم اجعل كلا الإعدادين
للقراءة فقط:
Age وExpires مع عمر العنصر المخزَّن مؤقتًا (بالثواني) والطابع الزمني لانتهاء صلاحيته.
تكون العناصر في ذاكرة التخزين المؤقت للاستعلام مضغوطة افتراضيًا. وهذا يقلل إجمالي استهلاك الذاكرة على حساب بطء عمليات الكتابة إلى / والقراءة
من ذاكرة التخزين المؤقت للاستعلام. لتعطيل الضغط، استخدم الإعداد query_cache_compress_entries.
أحيانًا يكون من المفيد الاحتفاظ بعدة نتائج مخزَّنة مؤقتًا للاستعلام نفسه. ويمكن تحقيق ذلك باستخدام الإعداد
query_cache_tag الذي يعمل كتسمية (أو مساحة اسم) لعناصر ذاكرة التخزين المؤقت للاستعلام. وتتعامل ذاكرة التخزين المؤقت للاستعلام
مع نتائج الاستعلام نفسه ذات الوسوم المختلفة على أنها مختلفة.
مثال على إنشاء ثلاثة عناصر مختلفة في ذاكرة التخزين المؤقت للاستعلام للاستعلام نفسه:
tag فقط من ذاكرة التخزين المؤقت للاستعلامات، يمكنك استخدام العبارة SYSTEM CLEAR QUERY CACHE TAG 'tag'.
التخزين المؤقت للاستعلامات الفرعية
use_query_cache في الاستعلام الخارجي، افتراضيًا، إلى الاستعلامات الفرعية. وهذا يعني أن على كل استعلام فرعي تفعيل التخزين المؤقت صراحةً:
query_cache_for_subqueries:
use_query_cache = false لهذا الاستعلام الفرعي:
is_subquery = 1. وينطبق الإعداد query_cache_ttl أيضًا على إدخالات ذاكرة التخزين المؤقت الخاصة بالاستعلامات الفرعية، ويمكن ضبطه لكل استعلام فرعي على حدة.
يقرأ ClickHouse بيانات الجدول في blocks من max_block_size rows. وبسبب التصفية وaggregation
وما إلى ذلك، تكون blocks النتائج عادةً أصغر بكثير من ‘max_block_size’، ولكن توجد أيضًا حالات تكون فيها أكبر بكثير. يتحكم الإعداد
query_cache_squash_partial_results (ممكّن افتراضيًا) في ما إذا كانت blocks النتائج
تُدمج (إذا كانت صغيرة جدًا) أو تُقسَّم (إذا كانت كبيرة) إلى blocks بحجم ‘max_block_size’ قبل إدراجها في ذاكرة التخزين المؤقت لنتيجة الاستعلام. ويؤدي ذلك إلى تقليل أداء عمليات الكتابة إلى ذاكرة التخزين المؤقت للاستعلامات، لكنه يحسّن معدل Compression لإدخالات ذاكرة التخزين المؤقت ويوفر
granularity أكثر طبيعية للـ block عند تقديم query results لاحقًا من ذاكرة التخزين المؤقت للاستعلامات.
ونتيجة لذلك، يخزّن ذاكرة التخزين المؤقت للاستعلامات لكل query عدة blocks نتائج (جزئية).
ورغم أن هذا السلوك يُعد خيارًا افتراضيًا جيدًا، يمكن تعطيله باستخدام الإعداد
query_cache_squash_partial_results.
كذلك، لا تُخزَّن نتائج queries التي تحتوي على دوال nondeterministic مؤقتًا افتراضيًا. وتشمل هذه الدوال:
- الدوال الخاصة بالوصول إلى Dictionaries:
dictGet()وغيرها. - الدوال المعرّفة من قبل المستخدم من دون الوسم
<deterministic>true</deterministic>في تعريف XML الخاص بها، - الدوال التي تُرجع التاريخ أو الوقت الحاليين:
now(),today(),yesterday()وغيرها، - الدوال التي تُرجع قيمًا عشوائية:
randomString(),fuzzBits()وغيرها، - الدوال التي تعتمد نتيجتها على الحجم والترتيب أو على chunks الداخلية المستخدمة في query processing:
nowInBlock()وغيرها،rowNumberInBlock(),runningDifference(),blockSize()وغيرها، - الدوال التي تعتمد على البيئة:
currentUser(),queryID(),getMacro()وغيرها.