استخدم الفهرس يا لوقا! › النصوص الرقمية 27 / 139 السابق التالي

السلاسل الرقمية

السلاسل الرقمية (numeric strings) أرقام مخزّنة في أعمدة نصية. ورغم أنها ممارسة سيئة للغاية، فإنها لا تجعل الفهرس عديم الفائدة تلقائياً إذا عاملتها باستمرار كسلسلة:

SELECT ...
  FROM ...
 WHERE numeric_string = '42'

بالطبع يمكن لهذه العبارة استخدام فهرس على NUMERIC_STRING. لكن إذا قارنتها باستخدام رقم، فلن تستطيع قاعدة البيانات (database) بعد ذلك استخدام هذا الشرط كـمُسند وصول.

SELECT ...
  FROM ...
 WHERE numeric_string = 42

لاحظ علامات الاقتباس الناقصة. ورغم أن بعض قواعد البيانات تُصدر خطأ (مثل PostgreSQL)، فإن قواعد بيانات كثيرة تضيف مجرد تحويل نوع ضمني.

SELECT ...
  FROM ...
 WHERE CAST(numeric_string AS INT) = 42

إنها المشكلة نفسها كما في السابق. فلا يمكن استخدام فهرس على NUMERIC_STRING بسبب نداء الدالة. والحل أيضاً هو نفسه: لا تحوّل عمود الجدول، بل حوّل مصطلح البحث.

SELECT ...
  FROM ...
 WHERE numeric_string = CAST(42 AS VARCHAR(10))

قد تتساءل لماذا لا تفعل قاعدة البيانات ذلك تلقائياً؟ أعتقد أن السبب أن تحويل سلسلة إلى رقم يعطي دائماً نتيجة لا لبس فيها. وهذا غير صحيح في الاتجاه المعاكس. فالرقم، عندما يُنسَّق كنص، قد يحتوي مسافات وعلامات ترقيم وأصفاراً بادئة. ويمكن كتابة القيمة الواحدة بطرق كثيرة:

42
042
0042
00042
...

لا يمكن لقاعدة البيانات معرفة تنسيق الأرقام المستخدم في العمود NUMERIC_STRING، لذا تفعل العكس: تحوّل قاعدة البيانات السلاسل إلى أرقام—وهذا تحويل لا لبس فيه.

إن أعجبك هذا الموضوع، قد يعجبك أيضاً…

… أن تشترك في القوائم البريدية، وتحصل على ملصقات مجانية، وتشتري كتابي، أو تنضم إلى دورة تدريبية.

يعيد تعبير CAST AS VARCHAR تمثيلاً نصياً واحداً فقط للرقم. لذا سيطابق أول سلسلة من القائمة أعلاه فقط. وإذا استخدمنا CAST AS INT، فإنه يطابقها جميعاً. ويعني ذلك أنه لا يوجد فرق في الأداء بين الصيغتين فحسب، بل فرق دلالي أيضاً!

استخدام السلاسل الرقمية مشكِل عموماً: فالأهم أنه يسبب مشكلات أداء بسبب التحويل الضمني، كما يطرح خطر الوقوع في أخطاء تحويل بسبب الأرقام غير الصالحة. وحتى أبسط استعلام لا يستخدم أي دوال في عبارة where قد يتوقف بسبب خطأ تحويل إذا كان في الجدول رقم غير صالح واحد فقط.

نصيحة

استخدم الأنواع الرقمية لتخزين الأرقام.

لاحظ أن المشكلة لا توجد في الاتجاه المعاكس:

SELECT ...
  FROM ...
 WHERE numeric_number = '42'

ستحوّل قاعدة البيانات السلسلة إلى رقم باستمرار. وهي لا تطبّق دالة على العمود القابل للفهرسة: لذا سيعمل الفهرس العادي. ومع ذلك يمكن إجراء تحويل يدوي بالطريقة الخاطئة:

SELECT ...
  FROM ...
 WHERE TO_CHAR(numeric_number) = '42'