mysql - 什么会导致连接比分成两个查询慢?

标签 mysql sql query-optimization faceted-search

我正在从多个表执行 JOIN 以执行分面搜索。当避免 JOIN 并将查询分成两个不同的查询时,我注意到性能得到了很大提升,所以我假设我的 JOIN 没有优化。

结构:

-- tags
userId  |   tagId
1              3
1              4
2              3
2              9

-- search
userId   |   number  |   countryId   |   stateId ...  
1              13           221             55

-- countries
countryId     |  countryName   
221                 Somewhere

-- users
userId    |   profileImageLink
1         |   <photo link>

我正在尝试提取所有具有标签的用户,根据 search.number 进行排序并从其他表中获取元数据。查询:

SELECT 
    search.*, users.a, users.b, users.c, users.d, users.e, users.f, countries.location_country, states.location_state, cities.location_city 
FROM search 
RIGHT JOIN tags 
   ON search.user_id = tags.user_id 
LEFT JOIN users 
   ON users.user_id=search.user_id 
LEFT JOIN countries 
   ON countries.countryId=search.countryId 
LEFT JOIN states 
   ON states.countryId=search.countryId AND states.stateId=search.stateId 
LEFT JOIN cities 
   ON cities.countryId=search.countryId AND cities.stateId=search.stateId AND cities.cityId=search.cityId 
WHERE 
  tags.skillId =52772 
ORDER BY 
  search.number DESC LIMIT 0,200

我注意到删除用户表的 JOIN(然后再这样做)使查询速度更快。我如何优化它以在同一个查询中工作?我试过将 FROM 更改为标签而不是搜索,但这没有用...

这是 EXPLAIN 显示的内容:

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   SIMPLE  tags    ref skill_user,skillId  skill_user  4   const   184854  Using index; Using temporary; Using filesort
1   SIMPLE  search  eq_ref  user_id user_id 4   tags.user_id    1   
1   SIMPLE  countries   eq_ref  PRIMARY PRIMARY 2   search.countryId    1   
1   SIMPLE  states  eq_ref  PRIMARY,state   PRIMARY 3   search.stateId  1   
1   SIMPLE  cities  eq_ref  PRIMARY,city    PRIMARY 3   search.cityId   1   
1   SIMPLE  users   eq_ref  user_id user_id 4   search.user_id  1   

EXPLAIN without the LEFT JOIN users:

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   SIMPLE  tags    ref skill_user,skillId  skill_user  4   const   155870  Using index
1   SIMPLE  search  eq_ref  user_id user_id 4   tags.user_id    1   
1   SIMPLE  countries   eq_ref  PRIMARY PRIMARY 2   search.countryId    1   
1   SIMPLE  states  eq_ref  PRIMARY,state   PRIMARY 3   search.stateId  1   
1   SIMPLE  cities  eq_ref  PRIMARY,city    PRIMARY 3   search.cityId   1   

EXPLAIN 答案中建议的查询:

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   SIMPLE  tags    index   NULL    userid_skill    8   NULL    22689539    Using where; Using index; Using temporary; Using filesort
1   SIMPLE  search  eq_ref  user_id user_id 4   tags.user_id    1   
1   SIMPLE  users   eq_ref  user_id user_id 4   search.user_id  1   
1   SIMPLE  countries   eq_ref  PRIMARY PRIMARY 2   search.countryId    1   
1   SIMPLE  states  eq_ref  PRIMARY,state   PRIMARY 3   search.stateId  1   
1   SIMPLE  cities  eq_ref  PRIMARY,city    PRIMARY 3   search.cityId   1   

最佳答案

在表上创建索引以运行以下查询:

Table    ColumnName
------   ----------
tags     user_id, skillid (Both column in one index)

试试这个:

SELECT s.*, u.a, u.b, u.c, u.d, u.e, u.f, c.location_country, 
       st.location_state, ct.location_city 
FROM tags t 
LEFT JOIN search s ON t.user_id = s.user_id 
LEFT JOIN users u ON t.user_id = u.user_id 
LEFT JOIN countries c ON s.countryId = c.countryId 
LEFT JOIN states st ON s.stateId = st.stateId 
LEFT JOIN cities ci ON s.cityId= ct.cityId 
WHERE t.skillId =52772 
ORDER BY s.number DESC 
LIMIT 0,200

编辑

使用适当的索引尝试这两个查询,让我知道以下查询是否适合您。

SELECT s.*, u.a, u.b, u.c, u.d, u.e, u.f, c.location_country, 
       st.location_state, ct.location_city 
FROM (SELECT user_id FROM tags WHERE t.skillId = 52772) AS t 
LEFT JOIN search s ON t.user_id = s.user_id 
LEFT JOIN users u ON t.user_id = u.user_id 
LEFT JOIN countries c ON s.countryId = c.countryId 
LEFT JOIN states st ON s.stateId = st.stateId 
LEFT JOIN cities ci ON s.cityId= ct.cityId 
ORDER BY s.number DESC 
LIMIT 0,200; 

SELECT s.*, u.a, u.b, u.c, u.d, u.e, u.f, c.location_country, 
       st.location_state, ct.location_city 
FROM (SELECT t.user_id, s.* FROM tags t 
      LEFT JOIN search s ON t.user_id = s.user_id  
      WHERE t.skillId = 52772 
      ORDER BY s.number DESC 
      LIMIT 0,200) AS t 
LEFT JOIN users u ON t.user_id = u.user_id 
LEFT JOIN countries c ON s.countryId = c.countryId 
LEFT JOIN states st ON s.stateId = st.stateId 
LEFT JOIN cities ci ON s.cityId= ct.cityId 
ORDER BY s.number DESC 
LIMIT 0,200; 

关于mysql - 什么会导致连接比分成两个查询慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14029714/

相关文章:

java - 受影响的行数, SQL

PHP:有什么更好的方法可以在不使用 IP 地址作为唯一标识符的情况下计算每台计算机的浏览量?

php - 当我尝试从 MySQL 检索信息时,我的页面崩溃了

java - 使用 sql 数据库数据填充 jtable 时出现 nullpointerException

mysql - 如何优化下面使用三级 select 语句的查询?

mysql - 如何与网络共享您在本地设置的网站

mysql - 获取数据库中varchar列的最大值

sql - 数据库ID最佳做法

sql-server - 如何使用 SQL 查询降低聚集索引扫描成本

Mysql Order BY 速度