Нечетное поведение MySQL - Справка по оптимизации запросов - PullRequest
0 голосов
/ 26 мая 2011

У нас есть центральный логин, который мы используем для поддержки нескольких веб-сайтов. Для хранения данных наших пользователей у нас есть таблица accounts, в которой хранится каждая учетная запись пользователя, а затем users таблицы для каждого сайта для конкретной информации о сайте.

Мы заметили, что один запрос, соединяющий таблицы по их первичному ключу user_id, выполняется медленно. Я надеюсь, что какой-нибудь эксперт по SQL сможет объяснить, почему он использует WHERE для поиска в таблице users_site1, и предложить, как мы можем ее оптимизировать. Вот медленный запрос и результаты объяснения:

mysql> explain select a.user_id as 'id',a.username,a.first_name as 'first',a.last_name as 'last',a.sex,u.user_id as 'profile',u.facebook_id as 'fb_id',u.facebook_publish as 'fb_publish',u.facebook_offline as 'fb_offline',u.twitter_id as 'tw_id',u.api_session as 'mobile',a.network from accounts a left join users_site1 u ON a.user_id=u.user_id AND u.status="R" where a.status="R" AND u.status="R" AND a.facebook_id='1234567890';
+----+-------------+-------+--------+----------------+---------+---------+-----------------------+-------+-------------+
| id | select_type | table | type   | possible_keys  | key     | key_len | ref                   | rows  | Extra       |
+----+-------------+-------+--------+----------------+---------+---------+-----------------------+-------+-------------+
|  1 | SIMPLE      | u     | ALL    | PRIMARY        | NULL    | NULL    | NULL                  | 79769 | Using where |
|  1 | SIMPLE      | a     | eq_ref | PRIMARY,status | PRIMARY | 4       | alltrailsdb.u.user_id |     1 | Using where |
+----+-------------+-------+--------+----------------+---------+---------+-----------------------+-------+-------------+
2 rows in set (0.00 sec)

Вот определения для каждой таблицы:

CREATE TABLE `accounts` (
  `user_id` int(9) unsigned NOT NULL AUTO_INCREMENT,
  `username` varchar(40) DEFAULT NULL,
  `facebook_id` bigint(15) unsigned DEFAULT NULL,
  `facebook_username` varchar(30) DEFAULT NULL,
  `password` varchar(20) DEFAULT NULL,
  `profile_photo` varchar(100) DEFAULT NULL,
  `first_name` varchar(40) DEFAULT NULL,
  `middle_name` varchar(40) DEFAULT NULL,
  `last_name` varchar(40) DEFAULT NULL,
  `suffix_name` char(3) DEFAULT NULL,
  `organization_name` varchar(100) DEFAULT NULL,
  `organization` tinyint(1) unsigned DEFAULT NULL,
  `address` varchar(200) DEFAULT NULL,
  `city` varchar(40) DEFAULT NULL,
  `state` varchar(20) DEFAULT NULL,
  `zip` varchar(10) DEFAULT NULL,
  `province` varchar(40) DEFAULT NULL,
  `country` int(3) DEFAULT NULL,
  `latitude` decimal(11,7) DEFAULT NULL,
  `longitude` decimal(12,7) DEFAULT NULL,
  `phone` varchar(20) DEFAULT NULL,
  `sex` char(1) DEFAULT NULL,
  `birthday` date DEFAULT NULL,
  `about_me` varchar(2000) DEFAULT NULL,
  `activities` varchar(300) DEFAULT NULL,
  `website` varchar(100) DEFAULT NULL,
  `email` varchar(150) DEFAULT NULL,
  `referrer` int(4) unsigned DEFAULT NULL,
  `referredid` int(9) unsigned DEFAULT NULL,
  `verify` int(6) DEFAULT NULL,
  `status` char(1) DEFAULT 'R',
  `created` datetime DEFAULT NULL,
  `verified` datetime DEFAULT NULL,
  `activated` datetime DEFAULT NULL,
  `network` datetime DEFAULT NULL,
  `deleted` datetime DEFAULT NULL,
  `logins` int(6) unsigned DEFAULT '0',
  `api_logins` int(6) unsigned DEFAULT '0',
  `last_login` datetime DEFAULT NULL,
  `last_update` datetime DEFAULT NULL,
  `private` tinyint(1) unsigned DEFAULT NULL,
  `ip` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`user_id`),
  UNIQUE KEY `username` (`username`),
  KEY `status` (`status`),
  KEY `state` (`state`)
);

CREATE TABLE `users_site1` (
  `user_id` int(9) unsigned NOT NULL,
  `facebook_id` bigint(15) unsigned DEFAULT NULL,
  `facebook_username` varchar(30) DEFAULT NULL,
  `facebook_publish` tinyint(1) unsigned DEFAULT NULL,
  `facebook_checkin` tinyint(1) unsigned DEFAULT NULL,
  `facebook_offline` varchar(300) DEFAULT NULL,
  `twitter_id` varchar(60) DEFAULT NULL,
  `twitter_secret` varchar(50) DEFAULT NULL,
  `twitter_username` varchar(20) DEFAULT NULL,
  `type` char(1) DEFAULT 'M',
  `referrer` int(4) unsigned DEFAULT NULL,
  `referredid` int(9) unsigned DEFAULT NULL,
  `session` varchar(60) DEFAULT NULL,
  `api_session` varchar(60) DEFAULT NULL,
  `status` char(1) DEFAULT 'R',
  `created` datetime DEFAULT NULL,
  `verified` datetime DEFAULT NULL,
  `activated` datetime DEFAULT NULL,
  `deleted` datetime DEFAULT NULL,
  `logins` int(6) unsigned DEFAULT '0',
  `api_logins` int(6) unsigned DEFAULT '0',
  `last_login` datetime DEFAULT NULL,
  `last_update` datetime DEFAULT NULL,
  `ip` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`user_id`)
);

Ответы [ 4 ]

1 голос
/ 26 мая 2011

Добавить индекс для столбца facebook_id в таблице accounts.

Текущий, MySql сканирует всю таблицу users, так как не может найти запись непосредственно в таблице account.

0 голосов
/ 26 мая 2011

Ваш запрос ищет строки в таблице accounts на основе идентификатора Facebook и учетной записи "status".У вас нет индексов, которые бы помогли с этим, поэтому MySQL выполняет сканирование таблицы.Я предлагаю следующий индекс:

ALTER TABLE accounts ADD INDEX (facebook_id, user_id)

Если хотите, вы можете даже включить в индекс столбец status.Является ли это хорошей идеей или нет, на самом деле зависит от того, поможет ли это сделать индекс привлекательным выбором для оптимизатора для любых других запросов, которые вы планируете выполнять.

PS.Комментарий "использование где" является нормальным и ожидается в большинстве запросов.Здесь следует обратить внимание на тот факт, что MySQL не использует индекс и считает, что должен проверять большое количество строк (конечно, это не должно иметь место, когда вы передаете конкретный идентификационный номер).

0 голосов
/ 26 мая 2011

Может быть, потому что вы не создали индексы для столбцов, по которым вы ищете ???Попробуйте проиндексировать столбцы, используемые в операторах соединения.Без индексации вы сканируете весь набор данных.

CREATE INDEX accounts_user_id_index ON accounts (user_id);
CREATE INDEX accounts.facebook_id_index ON accounts (status);
CREATE INDEX user_site1.user_id_index ON user_site1 (user_id);
0 голосов
/ 26 мая 2011

Минимум создайте 3 индекса на accounts.user_id, user_site1.user_id и accounts.facebook_id. Вполне вероятно, что индексы user_id уже существуют, поскольку они определены как PK.

...