سؤال

أنا أعمل على متجر إلكتروني يبيع المنتجات فقط عبر القروض. أعرض 10 منتجات لكل صفحة في أي فئة ، لكل منتج 3 علامات أسعار مختلفة - 3 أنواع قروض مختلفة. سارت الأمور على ما يرام أثناء وقت الاختبار ، كان وقت تنفيذ الاستعلام مثاليًا ، ولكن اليوم عند نقل التغييرات إلى خادم الإنتاج ، "انهار" الموقع في حوالي دقيقتين. الاستعلام الذي يتم استخدامه لتحديد أنواع القروض معلقة في بعض الأحيان لمدة 10 ثوانٍ تقريبًا ويحدث بشكل متكرر ، وبالتالي لا يمكنه مواكبة ذلك هيلا بطيئة. يحتوي الجدول المستخدم لتخزين البيانات على حوالي 2 ميليون ، ويبدو كل مختارة مثل هذا:

SELECT * 
FROM products_loans 
WHERE KOD IN("X17/Q30-10", "X17/12", "X17/5-24") 
AND 369.27 BETWEEN CENA_OD AND CENA_DO;

3 أنواع القروض والسعر الذي يجب أن يكون في المدى بين CENA_OD و CENA_DO ، وبالتالي يتم إرجاع 3 صفوف.

ولكن بما أنني بحاجة إلى عرض 10 منتجات لكل صفحة ، فأنا بحاجة إلى تشغيله أو, ، لأنني لم أجد أي حل آخر لهذا. لقد سألت عن ذلك هنا, ، لكن لم تحصل على إجابة. كما ذكر في منشور المرجع ، يجب القيام بذلك بشكل منفصل لأنه يوجد لا العمود الذي يمكن استخدامه في انضمام (باستثناء سعر الدورة التدريبية والرمز ، ولكن هذا انتهى بشكل سيء للغاية). ها هو show create table, و KOD و CENA_OD/CENA_DO فهرسة للغاية عبر الفهرس.

CREATE TABLE `products_loans` (
  `KOEF_ID` bigint(20) NOT NULL,
  `KOD` varchar(30) NOT NULL,
  `AKONTACIA` int(11) NOT NULL,
  `POCET_SPLATOK` int(11) NOT NULL,
  `koeficient` decimal(10,2) NOT NULL default '0.00',
  `CENA_OD` decimal(10,2) default NULL,
  `CENA_DO` decimal(10,2) default NULL,
  `PREDAJNA_CENA` decimal(10,2) default NULL,
  `AKONTACIA_SUMA` decimal(10,2) default NULL,
  `TYP_VYHODY` varchar(4) default NULL,
  `stage` smallint(6) NOT NULL default '1',
 PRIMARY KEY  (`KOEF_ID`),
 KEY `CENA_OD` (`CENA_OD`),
 KEY `CENA_DO` (`CENA_DO`),
 KEY `KOD` (`KOD`),
 KEY `stage` (`stage`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

وأيضًا اختيار جميع أنواع القروض وتصفيةها لاحقًا لا يعمل PHP بشكل جيد ، لأن كل نوع يحتوي على أكثر من 50 ألف سجل ويستغرق Select الكثير من الوقت أيضًا ...

أي معرفات حول تحسين السرعة موضع تقدير.

تعديل:

هنا هو التوضيح

+----+-------------+----------------+-------+---------------------+------+---------+------+--------+-------------+
| id | select_type | table          | type  | possible_keys       | key  | key_len | ref  | rows   | Extra       |
+----+-------------+----------------+-------+---------------------+------+---------+------+--------+-------------+
|  1 | SIMPLE      | products_loans | range | CENA_OD,CENA_DO,KOD | KOD  | 92      | NULL | 190158 | Using where |
+----+-------------+----------------+-------+---------------------+------+---------+------+--------+-------------+

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

هل كانت مفيدة؟

المحلول

حاول إعادة تشكيل استفسارك مثل:

SELECT * FROM products_loans 
WHERE KOD IN("X17/Q30-10", "X17/12", "X17/5-24") 
AND CENA_OD >= 369.27
AND CENA_DO <= 369.27;

(MySQL ليس ذكيًا جدًا عند اختيار الفهارس) والتحقق من الأداء.

المحاولة التالية هي إضافة مفتاح مشترك - (KOD ، CENA_OD ، CENA_DO)

والمحاولة الرئيسية التالية هي إعادة صياغة قاعدتك لفصل المنتجات عن الأسعار. هذا يجب أن يساعد حقا.

ملاحظة: يمكنك أيضًا الترحيل إلى PostgreSQL ، إنه أكثر ذكاءً من MySQL عند اختيار الفهارس الصحيحة.

نصائح أخرى

مشكلتك هي أنك تبحث عن فترات تحتوي على نقطة (بدلاً من الاستعلام الطبيعي لجميع النقاط في الفاصل الزمني). لا تعمل هذه الاستعلامات بشكل جيد مع فهرس B-Tree القياسي ، لذا بدلاً من ذلك تحتاج إلى استخدام فهرس R-Tree. لسوء الحظ ، لا يسمح لك MySQL بتحديد فهرس R-Tree على عمود ، ولكن يمكنك الحصول على الفهرس المطلوب عن طريق تغيير نوع العمود إلى الهندسة واستخدام الوظائف الهندسية للتحقق مما إذا كان الفاصل الزمني يحتوي على النقطة.

يرى Quassnoiمقالة قائمة المجاورة مقابل مجموعات متداخلة: MySQL حيث يشرح هذا بمزيد من التفصيل. حالة الاستخدام مختلفة ، لكن التقنيات المعنية هي نفسها. إليك مقتطف من الجزء ذي الصلة من المقال:

هناك أيضًا فئة معينة من المهام التي تتطلب البحث عن جميع النطاقات التي تحتوي على قيمة معروفة:

  • البحث عن عنوان IP في قائمة حظر نطاق IP
  • البحث عن تاريخ معين في نطاق تاريخ

والعديد من الآخرين. يمكن تحسين هذه المهام باستخدام إمكانيات R-Tree of MySQL.

يمكن لـ MySQL استخدام مفتاح واحد فقط. إذا كنت تحصل دائمًا على الإدخال بواسطة الأعمدة الثلاثة ، اعتمادًا على البيانات الفعلية (النطاق) في الأعمدة ، يمكن أن تضيف إحدى ما يلي قدرًا كبيرًا من الأداء:

ALTER TABLE products_loans ADD INDEX(KOD, CENA_OD, CENA_DO);
ALTER TABLE products_loans ADD INDEX(CENA_OD, CENA_DO, KOD);

لاحظ أن ترتيب الأعمدة مهم! إذا لم يحسن هذا الأداء ، فاعطينا EXPLAIN إخراج الاستعلام.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top