Нужна помощь в оптимизации sql JOIN запросов и индексов для больших таблиц - PullRequest
0 голосов
/ 23 февраля 2020

У меня есть запрос с JOIN для трех таблиц, выполнение которого занимает очень много времени. Я создал индекс для одной из моих таблиц для внешнего ключа (user_shared_url_id) и двух столбцов (event_result, enabled) в предложении WHERE, так что это индекс из трех столбцов. Кажется, ничем не отличается от того, когда я просто использую индекс внешнего ключа (user_shared_url_id). Две другие таблицы используют индексы одного столбца. Моя таблица пользователей содержит около 20 000 строк, но две другие таблицы довольно большие, с ~ 20 миллионами строк. Я не могу получить запрос, который занимает менее минуты или около того до sh. Кто-нибудь может подумать о каких-либо потенциальных оптимизациях, которые я могу сделать, чтобы ускорить это? Существуют ли другие индексы или улучшения моего пользовательского индекса, с которыми я могу работать?

Таблицы:


 CREATE TABLE `users` (
  `user_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `roles` varchar(500) DEFAULT NULL,
  `first_name` varchar(200) DEFAULT NULL,
  `last_name` varchar(100) DEFAULT NULL,
  `org_id` int(11) unsigned NOT NULL,
  `user_email` varchar(100) NOT NULL,
  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`user_id`),
  KEY `org_id` (`org_id`),
  KEY `status` (`status`),
  KEY `org_id_user_id` (`org_id`,`user_id`)
) ENGINE=MyISAM AUTO_INCREMENT=162524 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC


 CREATE TABLE `user_shared_urls` (
  `user_id` int(11) unsigned NOT NULL,
  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `user_shared_url_id` int(11) NOT NULL AUTO_INCREMENT,
  `target_url` text,
  PRIMARY KEY (`user_shared_url_id`),
  KEY `user_id` (`user_id`),
  KEY `user_id_usu_id` (`user_id`,`user_shared_url_id`)
) ENGINE=InnoDB AUTO_INCREMENT=62449105 DEFAULT CHARSET=utf8 |


 CREATE TABLE `user_share_events` (
  `user_share_event_id` int(11) NOT NULL AUTO_INCREMENT,
  `event_result` tinyint(1) unsigned DEFAULT NULL,
  `user_shared_url_id` int(11) NOT NULL,
  `enabled` tinyint(1) NOT NULL DEFAULT '1',
  PRIMARY KEY (`user_share_event_id`),
  KEY `user_shared_url_id` (`user_shared_url_id`),
  KEY `usuid_enabled_result` (`user_shared_url_id`,`enabled`,`event_result`)
) ENGINE=InnoDB AUTO_INCREMENT=35067339 DEFAULT CHARSET=utf8 |

Мои индексы:

CREATE INDEX org_id_user_id ON users(org_id, user_id);
CREATE INDEX user_id_usu_id ON user_shared_urls(user_id, user_shared_url_id);
CREATE INDEX usuid_enabled_result ON user_share_events(user_shared_url_id,enabled,event_result);

Мой запрос:

SELECT
    users.user_id,
    users.user_email "user_email",
    users.roles "role",
    CONCAT(users.first_name, ' ', users.last_name) "name",
    usus.target_url
FROM
    users
    JOIN user_shared_urls usus ON usus.user_id = users.user_id
    JOIN user_share_events uses ON usus.user_shared_url_id = uses.user_shared_url_id 
WHERE
    users.org_id = 1523
    AND
    uses.enabled = '1'
    AND
    uses.event_result = 1

Объяснить вывод вышеуказанного запроса:

+----+-------------+-------+------+----------------------------------------------------------------------------------+--------------------+---------+--------------------------------+------+-------------+
| id | select_type | table | type | possible_keys                                                                    | key                | key_len | ref                            | rows | Extra       |
+----+-------------+-------+------+----------------------------------------------------------------------------------+--------------------+---------+--------------------------------+------+-------------+
|  1 | SIMPLE      | users | ref  | PRIMARY,org_id,org_id_user_id                                                    | org_id             | 4       | const                          | 1235 | NULL        |
|  1 | SIMPLE      | usus  | ref  | PRIMARY,user_id,user_id_usu_id                                                   | user_id_usu_id     | 4       | luster.users.user_id           |  213 | NULL        |
|  1 | SIMPLE      | uses  | ref  | user_shared_url_id,user_and_service,result_service_occurred,usuid_enabled_result | user_shared_url_id | 4       | luster.usus.user_shared_url_id |    1 | Using where |
+----+-------------+-------+------+----------------------------------------------------------------------------------+--------------------+---------+--------------------------------+------+-------------+
3 rows in set (0.00 sec)

Ответы [ 2 ]

1 голос
/ 23 февраля 2020

Для этого запроса:

SELECT u.user_id, u.user_email, u.roles "role",
       CONCAT(u.first_name, ' ', u.last_name) "name",
       usu.target_url
FROM user_shared_urls usu JOIN
     users u
     ON usu.user_id = u.user_id JOIN
     user_share_events usev
     ON usus.user_shared_url_id = usev.user_shared_url_id 
WHERE u.org_id = 1010 AND
      usev.event_result IS NOT NULL AND
      usev.enabled = 1;

Вероятно, лучшие показатели:

  • users(org_id, user_id)
  • user_shared_urls(user_id, user_shared_url_id)
  • user_share_events(user_shared_url_id, enabled, event_result)

Это предполагает, что фильтрация на org_id является более избирательной, чем другие фильтры.

1 голос
/ 23 февраля 2020

(Пожалуйста, используйте SHOW CREATE TABLE; это более наглядно, чем DESCRIBE.)

Измените индекс, который вы добавили, на

INDEX(user_shared_url_id,     -- = and used for the JOIN
      enabled,                -- =
      event_result)           -- Last (not an = test)

Порядок столбцов в INDEX является важным. Начните со столбцов, которые проверены на = (или IS NULL).

Затем удалите FORCE INDEX и снова запустите EXPLAIN.

Эти таблицы находятся в 1:many отношения? Скажите нам, в каком направлении.

Еще один комментарий: если event_result действительно имеет только два значения (true / false) и вы используете NULL для false, то измените запрос с

uses.event_result IS NOT NULL

до

uses.event_result = 1

Дело в том, что Оптимизатор любит оптимизировать =, но видит NOT NULL как любое из 256 возможных значений; очень далеко от =. С этим запросом изменения ваш индекс должен работать. И даже быть выбранным без использования FORCE.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...