Тот же путь выполнения, данные и схемы; разное время запроса - PullRequest
9 голосов
/ 31 мая 2019

Мы заметили некоторые несоответствия в производительности MySQL для времени запросов, которые, по нашему мнению, не могут быть объяснены только нагрузкой на сервер.Некоторые запросы кажутся гораздо более эффективными, чем другие, несмотря на наличие аналогичной настройки.

Редактировать: С момента открытия этого вопроса наша база данных потерпела крах (по неизвестным причинам в данный момент команды RDS проводят расследование) и после перезагрузкипроблема больше не воспроизводима, и запросы имеют одинаковую скорость.Я все еще хотел бы знать, что было не так, потому что проблема может вернуться, но, возможно, мы никогда не узнаем ...

Продолжить оригинальный вопрос: Чтобы проверить это, я сделал почти копию таблицы.Производительность (время запроса) для скопированной таблицы значительно хуже, чем у исходного, несмотря на тот же путь выполнения, те же данные и очень похожие схемы таблиц.

В этом примере у нас есть следующие 3 таблицы:

  • offer_clicks

  • предложений

  • offer_new

«offer_new» - это тестовая таблица, которая имеет ограниченное количество полей (только поля «id» и «status»), но в остальном имеет ту же структуру, что и таблица «offer» (которая также имеет «id» и «status»)поле, но также много других полей.) Вот схемы таблиц:

Таблица предложений:

| offers | CREATE TABLE `offers` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `status` tinyint(4) NOT NULL DEFAULT '0',
  `user_id` int(11) NOT NULL DEFAULT '0',
.....many_other_fields.....
  KEY `ix_public_view_key` (`public_view_key`),
  FULLTEXT KEY `name` (`name`,`internal_name`)
) ENGINE=InnoDB AUTO_INCREMENT=18425582 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci |

Предложения Новая таблица:

| offers_new | CREATE TABLE `offers_new` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `status` tinyint(4) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=18423831 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci |

Затем мы сделалиВСТАВИТЬ ВЫБОР из таблицы «предложений» в таблицу «предложений»:

INSERT INTO offers_new (id, status) SELECT id, status FROM offers;

После этого мы начали выполнять несколько тестовых запросов. Как вы можете видеть, время запроса к «offer_new»Таблица "примерно в 10 раз медленнее таблицы" Предложения ".

mysql> SELECT COUNT(*) FROM offers_clicks, offers_new WHERE offers_new.id = offers_clicks.offer_id AND offers_clicks.date > '2019-05-30 00:00:00' and offers_clicks.date < '2019-05-30 01:00:00';
+----------+
| COUNT(*) |
+----------+
|    15472 |
+----------+
1 row in set (26.04 sec)

mysql> SELECT COUNT(*) FROM offers_clicks, offers WHERE offers.id  = offers_clicks.offer_id AND offers_clicks.date > '2019-05-30 00:00:00' and offers_clicks.date < '2019-05-30 01:00:00';
+----------+
| COUNT(*) |
+----------+
|    15472 |
+----------+
1 row in set (2.90 sec)

mysql> SELECT COUNT(*) FROM offers_clicks, offers_new WHERE offers_new.id = offers_clicks.offer_id AND offers_clicks.date > '2019-05-30 00:00:00' and offers_clicks.date < '2019-05-30 01:00:00';
+----------+
| COUNT(*) |
+----------+
|    15472 |
+----------+
1 row in set (28.07 sec)

mysql> SELECT COUNT(*) FROM offers_clicks, offers WHERE offers.id  = offers_clicks.offer_id AND offers_clicks.date > '2019-05-30 00:00:00' and offers_clicks.date < '2019-05-30 01:00:00';
+----------+
| COUNT(*) |
+----------+
|    15472 |
+----------+
1 row in set (2.26 sec)

Обратите внимание, чтоПуть выполнения одинаков для обоих запросов:

mysql> explain SELECT COUNT(*) FROM offers_clicks, offers_new WHERE offers_new.id = offers_clicks.offer_id AND offers_clicks.date > '2019-05-30 00:00:00' and offers_clicks.date < '2019-05-30 01:00:00';
+----+-------------+---------------+-----------------------------------------------------------------------+--------+--------------------+---------+---------+--------------------------------------------+-------+----------+-----------------------+
| id | select_type | table         | partitions                                                            | type   | possible_keys      | key     | key_len | ref                                        | rows  | filtered | Extra                 |
+----+
|  1 | SIMPLE      | offers_clicks | p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19 | range  | pts_id,date,date_2 | date    | 5       | NULL                                       | 15472 |   100.00 | Using index condition |
|  1 | SIMPLE      | offers_new    | NULL                                                                  | eq_ref | PRIMARY            | PRIMARY | 4       | dejong_pointstoshop.offers_clicks.offer_id |     1 |   100.00 | Using index           |
+----+
2 rows in set, 1 warning (0.00 sec)

mysql> explain SELECT COUNT(*) FROM offers_clicks, offers WHERE offers.id = offers_clicks.offer_id AND offers_clicks.date > '2019-05-30 00:00:00' and offers_clicks.date < '2019-05-30 01:00:00';
+----+-------------+---------------+-----------------------------------------------------------------------+--------+--------------------+---------+---------+--------------------------------------------+-------+----------+-----------------------+
| id | select_type | table         | partitions                                                            | type   | possible_keys      | key     | key_len | ref                                        | rows  | filtered | Extra                 |
+----+-------------+---------------+-----------------------------------------------------------------------+--------+--------------------+---------+---------+--------------------------------------------+-------+----------+-----------------------+
|  1 | SIMPLE      | offers_clicks | p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19 | range  | pts_id,date,date_2 | date    | 5       | NULL                                       | 15472 |   100.00 | Using index condition |
|  1 | SIMPLE      | offers        | NULL                                                                  | eq_ref | PRIMARY            | PRIMARY | 4       | dejong_pointstoshop.offers_clicks.offer_id |     1 |   100.00 | Using index           |
+----+-------------+---------------+-----------------------------------------------------------------------+--------+--------------------+---------+---------+--------------------------------------------+-------+----------+-----------------------+
2 rows in set, 1 warning (0.00 sec)

Шаги, которые мы предприняли после этого:

  • Мы обратились к нашему хосту, AWS, чтобы посмотреть, есть лилюбые проблемы с нашей настройкой RDS.Они сообщили, что не могут найти что-то не так, и утверждают, что это должно быть что-то не так с MySQL
  • Мы запустили профилирование, чтобы посмотреть, что происходит внутри.Мы не видим подмены, основные ошибки страниц (только незначительные) или другие вещи, которые могут объяснить различия.Я приложил данные в нижней части этого раздела.
  • Мы позаботились о том, чтобы оптимизировать таблицу, чтобы убедиться, что она как-то не фрагментирована, даже если это кажется маловероятным для новой таблицы.
  • Мы попытались убедиться, что таблица «offer_new» была «теплой», загрузив запрос несколько раз перед его синхронизацией.
  • Мы запустили эти запросы в нашей промежуточной среде и увидели, что производительность равна (таблица предложений_new)немного быстрее, возможно, из-за меньшего количества полей)

Мы используем MySQL 8.0.15

Стоит отметить, что наша производственная система находится под высокой загрузкой процессора.Однако это не должно объяснять разное время запросов для запросов, которые в значительной степени идентичны.Мы запустили его десятки раз с теми же результатами.

Стоит также отметить, что таблица «предложения» является рабочей таблицей, поэтому ее часто обновляют / запрашивают.«предложения_новой», которая является медленной таблицей, не является.

Изменения основаны на комментариях:

  • ANSI JOIN имеет те же результаты
  • Как и один комментатор, мы подумали, что, возможно, что-то не было в памяти для «offer_new».В конце концов, «offer_new» не используется в производстве, а «предложения» есть.Однако профилирование показывает «Page_faults_major» в 0 для обоих запросов.Хотя наше понимание в этой области довольно ограничено, мы считаем, что это означает, что данные были загружены из памяти, а не с диска.
  • Один комментатор попросил нас запустить COUNT только для таблиц «offer» и «offer_new».Вот результаты:
mysql> SELECT COUNT(*) FROM offers_new;
+----------+
| COUNT(*) |
+----------+
|  5093127 |
+----------+
1 row in set (0.13 sec)

mysql> SELECT COUNT(*) FROM offers;
+----------+
| COUNT(*) |
+----------+
|  5107742 |
+----------+
1 row in set (2.54 sec)

Счет очень близок. Offers - это живая таблица, поэтому со времени моих тестов вчера в таблицу были добавлены новые записи. Счет все еще близок, хотя. Интересно, что COUNT (*) для «offer_new» значительно быстрее, чем «предложения», поэтому в противоположность результатам запроса, о котором мы задали этот вопрос! Счет на «offer_new» составляет около 0,1 / 0,2 секунды, на таблицу «предложений» - несколько секунд (диапазон от 2 до 6 секунд). Я запускал его примерно по 10 раз каждый, чтобы убедиться, что это не просто загрузка сервера, и она была постоянно медленнее. Я предполагаю, что это как-то связано с количеством столбцов, которое намного больше для таблицы «предложений». В любом случае, интересно увидеть противоположные результаты другого запроса ...

Вот профилирование:

mysql> SHOW PROFILES;
+----------+-------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Query_ID | Duration    | Query                                                                                                                                                                                     |
+---+
|        1 | 26.03997750 | SELECT COUNT(*) FROM offers_clicks, offers_new WHERE offers_new.id = offers_clicks.offer_id AND offers_clicks.date > '2019-05-30 00:00:00' and offers_clicks.date < '2019-05-30 01:00:00' |
|        2 |  2.89890600 | SELECT COUNT(*) FROM offers_clicks, offers WHERE offers.id = offers_clicks.offer_id AND offers_clicks.date > '2019-05-30 00:00:00' and offers_clicks.date < '2019-05-30 01:00:00'         |
|        3 | 28.07228225 | SELECT COUNT(*) FROM offers_clicks, offers_new WHERE offers_new.id = offers_clicks.offer_id AND offers_clicks.date > '2019-05-30 00:00:00' and offers_clicks.date < '2019-05-30 01:00:00' |
|        4 |  2.25160675 | SELECT COUNT(*) FROM offers_clicks, offers WHERE offers.id = offers_clicks.offer_id AND offers_clicks.date > '2019-05-30 00:00:00' and offers_clicks.date < '2019-05-30 01:00:00'         |
+----------+-------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
4 rows in set, 1 warning (0.00 sec)

mysql> SHOW PROFILE ALL FOR QUERY 1;
+---+
| Status                         | Duration  | CPU_user   | CPU_system | Context_voluntary | Context_involuntary | Block_ops_in | Block_ops_out | Messages_sent | Messages_received | Page_faults_major | Page_faults_minor | Swaps | Source_function         | Source_file          | Source_line |
+---+
| starting                       |  0.000364 |   0.016000 |   0.000000 |                 3 |                   3 |            0 |             0 |             0 |                 0 |                 0 |                 1 |     0 | NULL                    | NULL                 |        NULL |
| Executing hook on transaction  |  0.000134 |   0.008000 |   0.000000 |                 6 |                   2 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | launch_hook_trans_begin | rpl_handler.cc       |        1100 |
| starting                       |  0.000128 |   0.008000 |   0.000000 |                 2 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | launch_hook_trans_begin | rpl_handler.cc       |        1102 |
| checking permissions           |  0.000173 |   0.008000 |   0.000000 |                 3 |                   2 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | check_access            | sql_authorization.cc |        1899 |
| checking permissions           |  0.000182 |   0.012000 |   0.000000 |                65 |                  33 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | check_access            | sql_authorization.cc |        1899 |
| Opening tables                 |  0.003432 |   0.176000 |   0.012000 |               556 |                 224 |            0 |             0 |             0 |                 0 |                 0 |                20 |     0 | open_tables             | sql_base.cc          |        5586 |
| init                           |  0.000235 |   0.012000 |   0.000000 |                25 |                  20 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | execute                 | sql_select.cc        |         555 |
| System lock                    |  0.000151 |   0.008000 |   0.000000 |                62 |                  17 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | mysql_lock_tables       | lock.cc              |         332 |
| optimizing                     |  0.000171 |   0.008000 |   0.000000 |                32 |                   9 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | optimize                | sql_optimizer.cc     |         212 |
| statistics                     |  0.001255 |   0.068000 |   0.000000 |               230 |                 125 |            0 |            24 |             0 |                 0 |                 0 |                 0 |     0 | optimize                | sql_optimizer.cc     |         425 |
| preparing                      |  0.000166 |   0.012000 |   0.000000 |                43 |                  19 |            0 |             0 |             0 |                 0 |                 0 |                10 |     0 | optimize                | sql_optimizer.cc     |         499 |
| executing                      |  0.000134 |   0.004000 |   0.000000 |                27 |                  16 |            0 |             0 |             0 |                 0 |                 0 |                10 |     0 | exec                    | sql_executor.cc      |         197 |
| Sending data                   | 26.032492 | 999.999999 |  67.940000 |           5361975 |             1420548 |       227416 |       1584568 |             0 |                 0 |                 0 |            299459 |     0 | exec                    | sql_executor.cc      |         273 |
| end                            |  0.000325 |   0.012000 |   0.000000 |                 7 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | execute                 | sql_select.cc        |         608 |
| query end                      |  0.000115 |   0.004000 |   0.000000 |                11 |                   9 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | mysql_execute_command   | sql_parse.cc         |        4581 |
| waiting for handler commit     |  0.000118 |   0.008000 |   0.000000 |                34 |                  13 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | ha_commit_trans         | handler.cc           |        1533 |
| closing tables                 |  0.000118 |   0.004000 |   0.000000 |                23 |                   2 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | mysql_execute_command   | sql_parse.cc         |        4627 |
| freeing items                  |  0.000163 |   0.008000 |   0.000000 |                 4 |                   1 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | mysql_parse             | sql_parse.cc         |        5256 |
| cleaning up                    |  0.000125 |   0.008000 |   0.000000 |                 5 |                   1 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | dispatch_command        | sql_parse.cc         |        2108 |
+---+
19 rows in set, 1 warning (0.00 sec)

mysql> SHOW PROFILE ALL FOR QUERY 2;
+---+
| Status                         | Duration | CPU_user   | CPU_system | Context_voluntary | Context_involuntary | Block_ops_in | Block_ops_out | Messages_sent | Messages_received | Page_faults_major | Page_faults_minor | Swaps | Source_function         | Source_file          | Source_line |
+---+
| starting                       | 0.000364 |   0.012000 |   0.000000 |                41 |                  24 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | NULL                    | NULL                 |        NULL |
| Executing hook on transaction  | 0.000137 |   0.008000 |   0.000000 |                40 |                  12 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | launch_hook_trans_begin | rpl_handler.cc       |        1100 |
| starting                       | 0.000135 |   0.004000 |   0.000000 |                21 |                   6 |            0 |            16 |             0 |                 0 |                 0 |                 2 |     0 | launch_hook_trans_begin | rpl_handler.cc       |        1102 |
| checking permissions           | 0.000124 |   0.008000 |   0.000000 |                26 |                   7 |            0 |            16 |             0 |                 0 |                 0 |                 2 |     0 | check_access            | sql_authorization.cc |        1899 |
| checking permissions           | 0.000139 |   0.008000 |   0.000000 |                19 |                   9 |           32 |            24 |             0 |                 0 |                 0 |                 4 |     0 | check_access            | sql_authorization.cc |        1899 |
| Opening tables                 | 0.000152 |   0.004000 |   0.000000 |                30 |                  14 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | open_tables             | sql_base.cc          |        5586 |
| init                           | 0.000125 |   0.004000 |   0.008000 |                25 |                  19 |            0 |             0 |             0 |                 0 |                 0 |                 1 |     0 | execute                 | sql_select.cc        |         555 |
| System lock                    | 0.000237 |   0.004000 |   0.004000 |                26 |                  15 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | mysql_lock_tables       | lock.cc              |         332 |
| optimizing                     | 0.000150 |   0.008000 |   0.000000 |                24 |                   7 |            0 |             0 |             0 |                 0 |                 0 |                 4 |     0 | optimize                | sql_optimizer.cc     |         212 |
| statistics                     | 0.001082 |   0.048000 |   0.004000 |               192 |                  59 |            0 |             0 |             0 |                 0 |                 0 |                17 |     0 | optimize                | sql_optimizer.cc     |         425 |
| preparing                      | 0.000162 |   0.008000 |   0.000000 |                19 |                  22 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | optimize                | sql_optimizer.cc     |         499 |
| executing                      | 0.000136 |   0.008000 |   0.000000 |                33 |                  32 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | exec                    | sql_executor.cc      |         197 |
| Sending data                   | 2.894895 | 120.524000 |   6.512000 |            551014 |              158606 |        43632 |        125120 |             0 |                 0 |                 0 |             34154 |     0 | exec                    | sql_executor.cc      |         273 |
| end                            | 0.000359 |   0.012000 |   0.000000 |                28 |                  27 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | execute                 | sql_select.cc        |         608 |
| query end                      | 0.000130 |   0.004000 |   0.004000 |                51 |                  33 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | mysql_execute_command   | sql_parse.cc         |        4581 |
| waiting for handler commit     | 0.000135 |   0.004000 |   0.000000 |                58 |                   9 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | ha_commit_trans         | handler.cc           |        1533 |
| closing tables                 | 0.000144 |   0.008000 |   0.000000 |                27 |                  15 |            0 |            16 |             0 |                 0 |                 0 |                 2 |     0 | mysql_execute_command   | sql_parse.cc         |        4627 |
| freeing items                  | 0.000165 |   0.008000 |   0.000000 |                23 |                   4 |            0 |             8 |             0 |                 0 |                 0 |                 3 |     0 | mysql_parse             | sql_parse.cc         |        5256 |
| cleaning up                    | 0.000137 |   0.008000 |   0.000000 |                 6 |                   3 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | dispatch_command        | sql_parse.cc         |        2108 |
+---+
19 rows in set, 1 warning (0.00 sec)
mysql> show create table offers \G
*************************** 1. row ***************************
       Table: offers
Create Table: CREATE TABLE `offers` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `status` tinyint(4) NOT NULL DEFAULT '0',
  `field_a` int(11) NOT NULL DEFAULT '0',
  `field_b` text COLLATE utf8_unicode_ci NOT NULL,
  `field_c` varchar(150) COLLATE utf8_unicode_ci NOT NULL,
  `field_d` text COLLATE utf8_unicode_ci NOT NULL,
  `field_e` text COLLATE utf8_unicode_ci NOT NULL,
  `field_f` text COLLATE utf8_unicode_ci,
  `field_g` varchar(64) CHARACTER SET utf8 DEFAULT NULL,
  `field_h` text COLLATE utf8_unicode_ci,
  `field_i` mediumint(9) NOT NULL DEFAULT '0',
  `field_j` varchar(100) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0',
  `field_k` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
  `field_l` decimal(10,4) NOT NULL,
  `field_m` decimal(10,4) NOT NULL DEFAULT '0.0000',
  `field_n` decimal(10,4) NOT NULL DEFAULT '0.0000',
  `field_o` decimal(10,4) NOT NULL DEFAULT '0.0000',
  `field_p` decimal(5,2) NOT NULL DEFAULT '0.00',
  `field_q` text COLLATE utf8_unicode_ci NOT NULL,
  `field_r` text COLLATE utf8_unicode_ci NOT NULL,
  `field_s` int(11) NOT NULL,
  `field_t` mediumint(9) NOT NULL DEFAULT '0',
  `field_u` tinyint(4) NOT NULL DEFAULT '0',
  `field_v` tinyint(4) NOT NULL DEFAULT '0',
  `field_w` tinyint(4) NOT NULL DEFAULT '0',
  `field_x` tinyint(4) NOT NULL,
  `field_y` tinyint(4) DEFAULT NULL,
  `field_z` tinyint(4) NOT NULL DEFAULT '0',
  `field_aa` tinyint(1) NOT NULL DEFAULT '0',
  `field_ab` tinyint(1) NOT NULL,
  `field_ac` tinyint(4) NOT NULL,
  `field_ad` tinyint(1) NOT NULL DEFAULT '0',
  `field_ae` tinyint(1) NOT NULL,
  `field_af` int(10) unsigned DEFAULT '0',
  `field_ag` int(10) unsigned NOT NULL,
  `field_ah` int(10) unsigned NOT NULL,
  `field_ai` int(11) NOT NULL,
  `field_aj` tinyint(1) NOT NULL DEFAULT '0',
  `field_ak` decimal(6,3) DEFAULT '0.000',
  `field_al` tinyint(1) NOT NULL,
  `field_am` decimal(8,3) NOT NULL,
  `field_an` decimal(8,3) NOT NULL,
  `field_ao` decimal(5,2) NOT NULL,
  `field_ap` decimal(8,3) NOT NULL,
  `field_aq` tinyint(3) unsigned DEFAULT NULL,
  `field_ar` int(11) NOT NULL,
  `field_as` mediumint(9) NOT NULL DEFAULT '0',
  `field_at` mediumint(9) NOT NULL,
  `field_au` mediumint(9) NOT NULL,
  `field_av` mediumint(9) NOT NULL,
  `field_aw` mediumint(9) NOT NULL,
  `field_ax` mediumint(9) NOT NULL DEFAULT '8388607',
  `field_ay` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  `field_az` tinyint(1) NOT NULL DEFAULT '0',
  `field_ba` smallint(5) unsigned DEFAULT NULL,
  `field_bb` tinyint(1) NOT NULL DEFAULT '0',
  `field_bc` tinyint(1) NOT NULL DEFAULT '0',
  `field_bd` tinyint(1) NOT NULL DEFAULT '1',
  `field_be` tinyint(1) NOT NULL,
  `field_bf` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  `field_bg` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `field_bh` tinyint(1) NOT NULL DEFAULT '0',
  `field_bi` text COLLATE utf8_unicode_ci NOT NULL,
  `field_bj` tinyint(1) NOT NULL DEFAULT '0',
  `field_bk` date DEFAULT NULL,
  `field_bl` date DEFAULT NULL,
  `field_bm` varchar(20) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
  `field_bn` varchar(40) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
  `field_bo` tinyint(1) NOT NULL DEFAULT '0',
  `field_bp` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `field_bq` smallint(5) unsigned DEFAULT NULL,
  `field_br` tinyint(3) unsigned NOT NULL DEFAULT '0',
  `field_bs` decimal(10,6) DEFAULT NULL,
  `field_bt` decimal(10,6) DEFAULT NULL,
  `field_bu` tinyint(1) NOT NULL DEFAULT '0',
  `field_bv` tinyint(1) NOT NULL DEFAULT '0',
  `field_bw` tinyint(1) NOT NULL DEFAULT '0',
  `field_bx` tinyint(1) NOT NULL DEFAULT '0',
  `field_by` tinyint(1) NOT NULL DEFAULT '0',
  `field_bz` datetime DEFAULT NULL,
  `field_ca` datetime DEFAULT NULL,
  `field_cb` datetime DEFAULT NULL,
  `field_cc` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
  `field_cd` datetime DEFAULT NULL,
  `field_ce` varchar(155) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
  `field_cf` int(11) DEFAULT NULL,
  `field_cg` decimal(10,4) NOT NULL DEFAULT '0.0000',
  `field_ch` tinyint(1) NOT NULL DEFAULT '0',
  `field_ci` decimal(5,4) NOT NULL DEFAULT '0.0000',
  `field_cj` mediumint(9) NOT NULL DEFAULT '0',
  `field_ck` datetime DEFAULT NULL,
  `field_cl` tinyint(1) NOT NULL DEFAULT '0',
  `field_cm` datetime DEFAULT NULL,
  `field_cn` smallint(5) unsigned NOT NULL DEFAULT '0',
  `field_co` smallint(5) unsigned NOT NULL DEFAULT '0',
  `field_cp` tinyint(1) NOT NULL DEFAULT '0',
  `field_cq` tinyint(1) NOT NULL DEFAULT '0',
  `field_cr` tinyint(1) NOT NULL DEFAULT '0',
  `field_cs` tinyint(1) NOT NULL DEFAULT '0',
  `field_ct` tinyint(1) NOT NULL DEFAULT '0',
  `field_cu` tinyint(1) NOT NULL DEFAULT '0',
  `field_cv` tinyint(1) NOT NULL DEFAULT '0',
  `field_cw` tinyint(1) NOT NULL DEFAULT '0',
  `field_cx` decimal(5,2) NOT NULL,
  `field_cy` tinyint(1) NOT NULL DEFAULT '0',
  `field_cz` tinyint(1) NOT NULL DEFAULT '0',
  `field_da` int(11) NOT NULL DEFAULT '0',
  `field_db` tinyint(1) NOT NULL DEFAULT '0',
  `field_dc` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
  `field_dd` tinyint(3) unsigned DEFAULT NULL,
  `field_de` tinyint(1) DEFAULT '0',
  `field_df` datetime DEFAULT NULL,
  `field_dg` tinyint(1) NOT NULL DEFAULT '0',
  `field_dh` tinyint(1) NOT NULL DEFAULT '0',
  `⁠⁠⁠⁠field_di` bigint(20) DEFAULT NULL,
  `field_dj` datetime DEFAULT NULL,
  `field_dk` tinyint(1) NOT NULL DEFAULT '0',
  `field_dl` int(1) DEFAULT NULL,
  `field_dm` tinyint(1) NOT NULL DEFAULT '0',
  `field_dn` int(11) NOT NULL DEFAULT '0',
  `field_do` tinyint(1) NOT NULL DEFAULT '0',
  `field_dp` tinyint(3) unsigned NOT NULL DEFAULT '0',
  `field_dq` int(11) NOT NULL DEFAULT '0',
  `field_dr` json DEFAULT NULL,
  `field_ds` int(11) NOT NULL DEFAULT '0',
  `field_dt` datetime DEFAULT NULL,
  `field_du` tinyint(1) NOT NULL DEFAULT '0',
  `field_dv` json NOT NULL,
  `field_dw` decimal(8,5) DEFAULT '0.00000',
  `field_dx` tinyint(1) NOT NULL DEFAULT '0',
  `field_dy` smallint(6) NOT NULL DEFAULT '14',
  PRIMARY KEY (`id`),
  UNIQUE KEY `field_i_field_j` (`field_i`,`field_j`),
  UNIQUE KEY `field_j_field_i` (`field_k`,`field_i`),
  KEY `status_field_bf` (`status`,`field_bf`),
  KEY `field_bm` (`field_bm`),
  KEY `status_field_i_field_bo` (`status`,`field_i`,`field_bo`),
  KEY `field_j` (`field_j`),
  KEY `field_bz` (`field_bz`),
  KEY `field_br` (`field_br`),
  KEY `field_bh` (`field_bh`),
  KEY `field_ba` (`field_ba`),
  KEY `field_cm` (`status`,`field_cm`),
  KEY `field_cc` (`field_cc`),
  KEY `field_i_field_cc` (`field_i`,`field_cc`),
  KEY `field_g` (`field_g`),
  FULLTEXT KEY `field_c` (`field_c`,`field_ce`)
) ENGINE=InnoDB AUTO_INCREMENT=18425582 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

1 Ответ

4 голосов
/ 04 июня 2019

Предположение (в ожидании дополнительной информации, запрошенной в комментариях) ...

  • innodb_buffer_pool_size меньше, чем Data_length (см. SHOW TABLE SIZE offers), и 15К строк разбросаны по всему столу.Это может привести к попаданию на диск вместо того, чтобы найти нужный id в кеше (buffer_pool).
  • Соотношение около 10: 1 , примером которого являются обе пары запусков,это то, что я видел много раз, сравнивая запрос, который попадает на диск, с запуском в кеше.

Частичное решение может быть увеличить buffer_pool ,Однако, поскольку вы используете облачную службу, единственный способ сделать это увеличение может состоять в том, чтобы заплатить за больший объем ОЗУ .

Альтернативой может быть принуждение или обманное использование другой индекс .Но сначала мне нужно увидеть остальные индексы, а также типы данных индексированных столбцов.

Между тем, я действительно хотел бы критиковать offers_clicks;что такое ключ раздела?

На другом подходе ... Это обычный запрос?Похоже, «сколько кликов произошло за час?»

Почему нужно вообще смотреть на offers?Разве он не может получить правильный ответ от SELECT COUNT(*) FROM offers_clicks WHERE date ...?

Если вам нужен JOIN, тогда давайте поговорим о построении и ведении сводной таблицы который содержит счет за каждый час.

Побочные вопросы

FROM offers_clicks, offers
WHERE offers.id = offers_clicks.offer_id AND offers_clicks.date

должно быть написано

FROM offers_clicks
JOIN offers  ON offers.id = offers_clicks.offer_id  -- how the tables relate
WHERE offers_clicks.date ...

Бывший старый "коммалист"стиль JOIN, последний - предпочтительный синтаксис .Два синтаксиса генерируют идентичный код, поэтому это не проблема производительности.Прежний выглядит как "перекрестное соединение", но WHERE делает его эффективным не.

Также ... Это всего лишь 3599 секунд, не полный час .Соглашение состоит в том, чтобы включать первую полночь.

    date > '2019-05-30 00:00:00'
and date < '2019-05-30 01:00:00'

Я предпочитаю этот стиль, поскольку он избегает проблем високосного года и т. Д .:

    date >= '2019-05-30 00:00:00'
and date  < '2019-05-30 00:00:00' + INTERVAL 1 HOUR

Ошибки страницы ...

Когда программа (MySQL или любая другая) выделила больше памяти (ОЗУ), чем операционная система готова предоставить, некоторые страницы (обычно размером 4 КБ) «выгружаются» на диск.Когда программа ссылается на страницу, возникает «ошибка страницы».Это аппаратное прерывание, которое говорит: «Паника! Запрошенная вами страница отсутствует в оперативной памяти».Затем операционная система вмешивается, чтобы скопировать эту страницу обратно в ОЗУ, чтобы программа могла продолжить работу.

InnoDB очень предпочел бы выложить большой объем ОЗУ, а затем иметь свободный доступ ко всему этому в любое время.То есть InnoDB делает вид, что сбои страниц никогда не произойдут.Следовательно, сбои страниц сильно снижают производительность .Не настраивайте MySQL для использования «слишком большого» объема ОЗУ, иначе вы попадете на сбои страниц.

InnoDB делает необходимым для замены блоков данных и индексов (и определений таблиц и т. Д.) В ОЗУи освободить место для других блоков.Но InnoDB тщательно разработан и закодирован, чтобы минимизировать это. «буферный пул» - это большой кусок оперативной памяти, который InnoDB использует в качестве LRU (наименее недавно использованного) кэша своих блоков по 16 КБ. То, что , вероятно, замедляет обработку, а не процессор, не сбои страниц и т. Д. (Я жду некоторой информации, чтобы подтвердить это.)

первый раз обычно медленнее , то есть, когда он показывает основные сбои страниц.Последующие запросы обычно выполняются быстро.

Это означает, что был ввод / вывод для ввода страниц, необходимых для запроса (главная ошибка страницы).Затем последующие запросы могут выполняться без ввода-вывода (быстрее).

И, поскольку offers намного больше, будет больше ввода-вывода.Однако это противоположно тому, что вы видите.

...