الفخات الفرعية و MySQL ذاكرة التخزين المؤقت لجدول الصفوف 18M+

StackOverflow https://stackoverflow.com/questions/4265544

سؤال

نظرًا لأن هذا هو أول مشاركة لي ، يبدو أنه لا يمكنني فقط نشر رابط واحد ، لذا فقد أدرجت المواقع التي أشير إليها في الأسفل. باختصار ، فإن هدفي هو جعل قاعدة البيانات تعيد النتائج بشكل أسرع ، لقد حاولت تضمين أكبر قدر من المعلومات ذات الصلة بقدر ما يمكن أن أفكر للمساعدة في تأطير الأسئلة في أسفل المنشور.

معلومات الآلة


8 processors
model name      : Intel(R) Xeon(R) CPU           E5440  @ 2.83GHz
cache size      : 6144 KB
cpu cores       : 4 

top - 17:11:48 up 35 days, 22:22, 10 users,  load average: 1.35, 4.89, 7.80
Tasks: 329 total,   1 running, 328 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.0%us,  0.0%sy,  0.0%ni, 87.4%id, 12.5%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:   8173980k total,  5374348k used,  2799632k free,    30148k buffers
Swap: 16777208k total,  6385312k used, 10391896k free,  2615836k cached

ومع ذلك ، فإننا نبحث في نقل تثبيت MySQL إلى جهاز مختلف في الكتلة التي تحتوي على 256 جيجابايت من ذاكرة الوصول العشوائي

معلومات الجدول


يبدو أن طاولة MySQL الخاصة بي

CREATE TABLE ClusterMatches 
(
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    cluster_index INT, 
    matches LONGTEXT,
    tfidf FLOAT,
    INDEX(cluster_index)   
);

إنه يحتوي على حوالي 18 مليون صف ، وهناك 1M 1M CLUSTER_INDEX'S و 6K فريدة من نوعها. يبدو استعلام SQL الذي أقوم بإنشائه في PHP.

استعلام SQL


$sql_query="SELECT `matches`,sum(`tfidf`) FROM 
(SELECT * FROM Test2_ClusterMatches WHERE `cluster_index` in (".$clusters.")) 
AS result GROUP BY `matches` ORDER BY sum(`tfidf`) DESC LIMIT 0, 10;";

حيث تحتوي مجموعة $ على سلسلة من حوالي 3000 فاصلة مفصولة cluster_index's. يستخدم هذا الاستعلام ما يقرب من 50000 صف ويستغرق حوالي 15s لتشغيله ، عندما يتم تشغيل الاستعلام نفسه مرة أخرى ، يستغرق تشغيل 1s تقريبًا.

الاستخدام


  1. يمكن افتراض أن محتوى الجدول ثابت.
  2. انخفاض عدد المستخدمين المتزامنين
  3. الاستعلام أعلاه هو حاليا الاستعلام الوحيد الذي سيتم تشغيله على الطاولة

مسمة فرعية


استنادًا إلى هذا المنشور [stackoverflow: ذاكرة التخزين المؤقت/إعادة استخدام مسمة فرعية في MySQL] [1] والتحسن في وقت الاستعلام ، أعتقد أنه يمكن فهرسة مساعتي الفرعية.

mysql> EXPLAIN EXTENDED SELECT `matches`,sum(`tfidf`) FROM 
(SELECT * FROM ClusterMatches WHERE `cluster_index` in (1,2,...,3000) 
AS result GROUP BY `matches` ORDER BY sum(`tfidf`) ASC LIMIT 0, 10;

+----+-------------+----------------------+-------+---------------+---------------+---------+------+-------+---------------------------------+
| id | select_type | table                | type  | possible_keys | key           | key_len | ref  | rows  | Extra                           |
+----+-------------+----------------------+-------+---------------+---------------+---------+------+-------+---------------------------------+
|  1 | PRIMARY     |  derived2            | ALL   | NULL          | NULL          | NULL    | NULL | 48528 | Using temporary; Using filesort | 
|  2 | DERIVED     | ClusterMatches       | range | cluster_index | cluster_index | 5       | NULL | 53689 | Using where                     | 
+----+-------------+----------------------+-------+---------------+---------------+---------+------+-------+---------------------------------+

وفقًا لهذه المقالة الأقدم [تحسين MySQL: الاستعلامات والفهارس] [2] في معلومات إضافية - المعلومات السيئة التي يمكن رؤيتها هنا هي "استخدام مؤقت" و "استخدام Filesort"

معلومات التكوين MySQL


تتوفر ذاكرة التخزين المؤقت للاستعلام ، ولكن يتم إيقاف تشغيلها بشكل فعال حيث يتم ضبط الحجم حاليًا على الصفر


mysqladmin variables;
+---------------------------------+----------------------+
| Variable_name                   | Value                |
+---------------------------------+----------------------+
| bdb_cache_size                  | 8384512              | 
| binlog_cache_size               | 32768                | 
| expire_logs_days                | 0                    |
| have_query_cache                | YES                  | 
| flush                           | OFF                  |
| flush_time                      | 0                    |
| innodb_additional_mem_pool_size | 1048576              |
| innodb_autoextend_increment     | 8                    |
| innodb_buffer_pool_awe_mem_mb   | 0                    |
| innodb_buffer_pool_size         | 8388608              |
| join_buffer_size                | 131072               |
| key_buffer_size                 | 8384512              |
| key_cache_age_threshold         | 300                  |
| key_cache_block_size            | 1024                 |
| key_cache_division_limit        | 100                  |
| max_binlog_cache_size           | 18446744073709547520 | 
| sort_buffer_size                | 2097144              |
| table_cache                     | 64                   | 
| thread_cache_size               | 0                    | 
| query_cache_limit               | 1048576              |
| query_cache_min_res_unit        | 4096                 |
| query_cache_size                | 0                    |
| query_cache_type                | ON                   |
| query_cache_wlock_invalidate    | OFF                  |
| read_rnd_buffer_size            | 262144               |
+---------------------------------+----------------------+

استنادًا إلى هذا المقال على [MySQL Database Performance Turning] [3] أعتقد أن القيم التي أحتاج إلى تعديلها

  1. table_cache
  2. key_buffer
  3. sort_buffer
  4. read_buffer_size
  5. record_rnd_buffer (للمجموعة حسب وترتيب المصطلحات)

المجالات المحددة للتحسين - تعديلات استعلام MySQL


  1. تغيير نوع البيانات للمطابقات إلى فهرس يشير إلى جدول آخر [سوف يستخدم MySQL بالفعل تنسيق صف ديناميكي إذا كان يحتوي . لا يهدف الحل إلى تجنب أنواع البيانات هذه ، بل تقسيم مثل هذه الحقول إلى جدول مرتبط.] [4
  2. فهرسة match_index feild جديدة بحيث تكون المجموعة بواسطة matches يحدث بشكل أسرع ، استنادًا إلى العبارة ["ربما يجب إنشاء مؤشرات لأي حقل تقوم به أو تجمعه أو طلبه أو الانضمام إليه."] [5

أدوات


لتعديل الأداء أخطط للاستخدام

  1. شرح] [6] الإشارة إلى [تنسيق الإخراج] [7
  2. AB - Apache HTTP Server Server Tool] [8
  3. التنميط] [9] مع [بيانات السجل] [10

حجم قاعدة البيانات في المستقبل


الهدف من ذلك هو إنشاء نظام يمكن أن يحتوي على قيم فريدة من نوعها cluster_index 1m ، حوالي 3،000،000،000 صفوف من الجدول مع وقت استجابة للاستعلام حوالي 0.5 ثانية (يمكننا إضافة المزيد من ذاكرة الوصول العشوائي حسب الضرورة وتوزيع قاعدة البيانات عبر المجموعة)

أسئلة


  1. أعتقد أننا نريد الاحتفاظ بمجموعة السجلات بأكملها في ذاكرة الوصول العشوائي بحيث لا يلمس الاستعلام القرص ، إذا احتفظنا بقاعدة البيانات بأكملها في ذاكرة التخزين المؤقت MySQL هل يلغي ذلك الحاجة إلى memcachedb؟
  2. هل تحاول الحفاظ على قاعدة البيانات بأكملها في ذاكرة التخزين المؤقت MySQL استراتيجية سيئة لأنها غير مصممة لتكون ثابتة؟ هل سيكون هناك شيء مثل memcachedb أو redis طريقة أفضل ، إذا كان الأمر كذلك ، فلماذا؟
  3. هل الجدول المؤقت "النتيجة" التي يتم إنشاؤها بواسطة الاستعلام دمر تلقائيًا عند انتهاء الاستعلام؟
  4. هل يجب أن نتحول من InnoDB إلى Myisam [باعتباره جيدًا لقراءة البيانات الثقيلة حيث يكون Innodb جيدًا للكتابة الثقيلة] [11]؟
  5. لا يبدو أن ذاكرة التخزين المؤقت الخاصة بي على أنها صفر في تكوين ذاكرة التخزين المؤقت [Query] [12] ، لماذا يحدث الاستعلام حاليًا بشكل أسرع في المرة الثانية التي أقوم فيها بتشغيله؟
  6. هل يمكنني إعادة هيكلة استعلامي للتخلص من "استخدام مؤقت" و "استخدام Filesort" ، هل يجب أن أستخدم انضمام بدلاً من مسافة فرعية؟
  7. كيف يمكنك عرض حجم mysql [ذاكرة التخزين المؤقت للبيانات] [13]؟
  8. أي نوع من الأحجام للقيم table_cache ، key_buffer ، sort_buffer ، read_buffer_size ، record_rnd_buffer هل تقترح كنقطة انطلاق؟

الروابط


  • 1: stackoverflow.com/questions/658937/cache-re-use-a-subquery-in-mysql
  • 2: databasejournal.com/features/mysql/article.php/10897_1382791_4/optimizing-mysql-queries-and-indexes.htm
  • 3: Debianhelp.co.uk/mysqlperformance.htm
  • 4: 20bits.com/articles/10-tips-for-optimizing-mysql-iredies- that-dont-suck/
  • 5: 20bits.com/articles/10-tips-for-optimizing-mysql-iredies- that-dont-suck/
  • 6: dev.mysql.com/doc/refman/5.0/en/explain.html
  • 7: dev.mysql.com/doc/refman/5.0/en/explain-output.html
  • 8: httpd.apache.org/docs/2.2/programs/ab.html
  • 9: mtop.sourceforge.net/
  • 10: dev.mysql.com/doc/refman/5.0/en/slow-query-log.html
  • 11: 20bits.com/articles/10-tips-for-optimizing-mysql-iredies- that-dont-suck/
  • 12: dev.mysql.com/doc/refman/5.0/en/query-cache-configuration.html
  • 13: dev.mysql.com/tech-resources/articles/mysql-query-cache.html
هل كانت مفيدة؟

المحلول

تغيير الجدول


بناءً على النصيحة في هذا المنشور كيفية اختيار فهارس للطلب من خلال مجموعة من الاستعلامات يبدو أن الجدول الآن

CREATE TABLE ClusterMatches 
(
    cluster_index INT UNSIGNED, 
    match_index INT UNSIGNED,
    id INT NOT NULL AUTO_INCREMENT,
    tfidf FLOAT,
    PRIMARY KEY (match_index,cluster_index,id,tfidf)
);
CREATE TABLE MatchLookup 
(
    match_index INT UNSIGNED NOT NULL PRIMARY KEY,
    image_match TINYTEXT
);

القضاء على الاسم الفرعي

يبدو الاستعلام دون فرز النتائج بواسطة Sum (TFIDF)

SELECT match_index, SUM(tfidf) FROM ClusterMatches 
WHERE cluster_index in (1,2,3 ... 3000) GROUP BY match_index LIMIT 10;

الذي يلغي باستخدام مؤقت واستخدام Filesort

explain extended SELECT match_index, SUM(tfidf) FROM ClusterMatches 
WHERE cluster_index in (1,2,3 ... 3000) GROUP BY match_index LIMIT 10;
+----+-------------+----------------------+-------+---------------+---------+---------+------+-------+--------------------------+
| id | select_type | table                | type  | possible_keys | key     | key_len | ref  | rows  | Extra                    |
+----+-------------+----------------------+-------+---------------+---------+---------+------+-------+--------------------------+
|  1 | SIMPLE      | ClusterMatches       | range | PRIMARY       | PRIMARY | 4       | NULL | 14938 | Using where; Using index | 
+----+-------------+----------------------+-------+---------------+---------+---------+------+-------+--------------------------+

مشكلة الفرز

ومع ذلك ، إذا قمت بإضافة الطلب حسب SUM (TFDIF) في

SELECT match_index, SUM(tfidf) AS total FROM ClusterMatches
WHERE cluster_index in (1,2,3 ... 3000) GROUP BY match_index 
ORDER BY total DESC LIMIT 0,10;
+-------------+--------------------+
| match_index | total              |
+-------------+--------------------+
|         868 |   0.11126546561718 | 
|        4182 | 0.0238558370620012 | 
|        2162 | 0.0216601379215717 | 
|        1406 | 0.0191618576645851 | 
|        4239 | 0.0168981291353703 | 
|        1437 | 0.0160425212234259 | 
|        2599 | 0.0156466849148273 | 
|         394 | 0.0155945559963584 | 
|        3116 | 0.0151005545631051 | 
|        4028 | 0.0149106932803988 | 
+-------------+--------------------+
10 rows in set (0.03 sec)

والنتيجة سريعة بشكل مناسب في هذا المقياس ولكن وجود الطلب حسب SUM (TFIDF) يعني أنه يستخدم مؤقتًا وملفات

explain extended SELECT match_index, SUM(tfidf) AS total FROM ClusterMatches 
WHERE cluster_index IN (1,2,3 ... 3000) GROUP BY match_index 
ORDER BY total DESC LIMIT 0,10;
+----+-------------+----------------------+-------+---------------+---------+---------+------+-------+-----------------------------------------------------------+
| id | select_type | table                | type  | possible_keys | key     | key_len | ref  | rows  | Extra                                                     |
+----+-------------+----------------------+-------+---------------+---------+---------+------+-------+-----------------------------------------------------------+
|  1 | SIMPLE      | ClusterMatches       | range | PRIMARY       | PRIMARY | 4       | NULL | 65369 | Using where; Using index; Using temporary; Using filesort | 
+----+-------------+----------------------+-------+---------------+---------+---------+------+-------+-----------------------------------------------------------+

الحلول الممكنة؟

أنا أبحث عن حل لا يستخدم مؤقتًا أو ملفات ، على غرار

SELECT match_index, SUM(tfidf) AS total FROM ClusterMatches 
WHERE cluster_index IN (1,2,3 ... 3000) GROUP BY cluster_index, match_index 
HAVING total>0.01 ORDER BY cluster_index;
حيث لا أحتاج إلى ترميز عتبة للإجمالي ، أي أفكار؟

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