简体   繁体   English

奇数 MySQL 行为 - 查询优化帮助

[英]Odd MySQL Behavior - Query Optimization Help

We have a central login that we use to support multiple websites.我们有一个用于支持多个网站的中央登录。 To store our users' data we have an accounts table which stores each user account and then users tables for each site for site specific information.为了存储我们用户的数据,我们有一个accounts表,该表存储每个用户帐户,然后是每个站点的users表,以获取站点特定信息。

We noticed that one query that is joining the tables on their primary key user_id is executing slowly.我们注意到,在主键user_id上加入表的一个查询执行缓慢。 I'm hoping that some SQL expert out there can explain why it's using WHERE to search the users_site1 table and suggest how we can optimize it.我希望那里的一些 SQL 专家可以解释为什么它使用WHERE搜索 users_site1 表并建议我们如何优化它。 Here is the slow query & the explain results:这是慢查询和解释结果:

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)

Here are the definitions for each table:以下是每个表的定义:

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`)
);

Add a index on the column facebook_id in the accounts table.accounts表中的facebook_id列上添加索引。

Current, MySql is scanning the entire users table, since it cannot find the record directly in the account table.当前,MySql 正在扫描整个users表,因为它无法直接在account表中找到记录。

The least create 3 indexes on accounts.user_id , user_site1.user_id and accounts.facebook_id .最少在accounts.user_iduser_site1.user_idaccounts.facebook_id上创建 3 个索引。 It's likely that user_id indexes already exist as they are defined as PKs though.很可能user_id索引已经存在,因为它们被定义为 PK。

Maybe because you haven't created indexes on the columns you're searching on???也许是因为您没有在要搜索的列上创建索引??? Try indexing the columns used on the join statements.尝试索引连接语句中使用的列。 Without indexing, you're scanning through all the dataset.如果没有索引,您将扫描所有数据集。

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);

Your query is looking for rows in table accounts based on the Facebook ID and on the account "status".您的查询正在根据 Facebook ID 和帐户“状态”在表accounts中查找行。 You don't have any indexes that help with this, so MySQL is doing a table scan.您没有任何索引对此有帮助,因此 MySQL 正在执行表扫描。 I suggest the following index:我建议以下索引:

ALTER TABLE accounts ADD INDEX (facebook_id, user_id)

If you wanted, you could even include the status column in the index.如果您愿意,您甚至可以在索引中包含status列。 Whether this is a good idea or not would really depend on whether or not it would help to make the index an attractive choice for the optimiser for any other queries you plan to run.这是否是一个好主意实际上取决于它是否有助于使索引成为您计划运行的任何其他查询的优化器的有吸引力的选择。

PS. PS。 The comment "using where" is normal and is to be expected in most queries.注释“使用 where”是正常的,并且在大多数查询中都是可以预期的。 The thing to be concerned about here is the fact that MySQL is not using an index, and that it thinks it has to examine a large number of rows (surely this should not be the case when you are passing in a specific ID number).这里要关心的是,MySQL 没有使用索引,它认为它必须检查大量行(当你传递一个特定的 ID 号时肯定不应该是这种情况)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM