SELECT i.*, i.id IN (
SELECT id
FROM w
WHERE w.status='active') AS wish
FROM i
INNER JOIN r ON i.id=r.id
WHERE r.member_id=1 && r.status='active'
ORDER BY wish DESC
LIMIT 0,50
这是我正在尝试运行的查询。它不能很好地扩展,我想知道这里是否有人可以告诉我在哪里可以改进。我不加入r和我,因为我需要显示来自i的行,这些行在w中没有代表。我尝试了左连接,但它的表现并不太好。这更好,但还不理想。所有三个表都非常大。所有这三个都在我加入并选择的字段上编入索引。
任何评论,指示或建设性批评都将不胜感激。
编辑增加:
我应该把这个放在原来的问题中。这是从SQLYog返回的EXPLAIN。
id|select_type |table|type |possible_keys|key |key_len|ref |rows|Extra|
1 |PRIMARY |r |ref |member_id,id |member_id|3 |const|3120|Using where; Using temporary; Using filesort
1 |PRIMARY |i |eq_ref |id |id |8 |r.id |1 |
2 |DEPENDENT SUBQUERY|w |index_subquery|id,status |id |8 |func |8 |Using where
<小时/> 编辑le dorfier - 更多评论......
我应该提到w的关键是(member_id,id)。所以每个id都可以在w中存在多次,我只想知道它是否存在。
答案 0 :(得分:3)
WHERE x IN ()
与INNER JOIN
到SELECT DISTINCT
子查询相同,一般情况下,如果优化程序不转{{1},则子查询的连接通常会更好进入IN
- 它应该:
JOIN
如果您不需要SELECT i.*
FROM i
INNER JOIN (
SELECT DISTINCT id
FROM w
WHERE w.status = 'active'
) AS wish
ON i.id = wish.id
INNER JOIN r
ON i.id = r.id
WHERE r.member_id = 1 && r.status = 'active'
ORDER BY wish.id DESC
LIMIT 0,50
:
DISTINCT
请发布您的架构。
如果您使用wish作为存在标志,请尝试:
SELECT i.*
FROM i
INNER JOIN w
ON w.status = 'active'
AND i.id = wish.id
INNER JOIN r
ON i.id = r.id
AND r.member_id = 1 && r.status = 'active'
ORDER BY i.id DESC
LIMIT 0,50
您可以使用与SELECT i.*, CASE WHEN w.id IS NOT NULL THEN 1 ELSE 0 END AS wish
FROM i
INNER JOIN r
ON i.id = r.id
AND r.member_id = 1 && r.status = 'active'
LEFT JOIN w
ON w.status = 'active'
AND i.id = w.id
ORDER BY wish DESC
LIMIT 0,50
到LEFT JOIN
子查询相同的技术。我假设您没有指定SELECT DISTINCT
,因为您想知道是否有会员这样做?在这种情况下,请务必使用w.member_id
。您应该将SELECT DISTINCT
的索引作为id
上的第一列,以便执行此操作:
w
答案 1 :(得分:1)
请发布EXPLAIN列表。并解释表格和列的含义。
愿望似乎是一个布尔值 - 而你正在按它排序?
狂野的猜测让每个人都感到困惑(包括你,我敢肯定。)
好的,根据新信息,这是我(稍微不那么狂野)的猜测。
SELECT i.*,
CASE WHEN EXISTS (SELECT 1 FROM w WHERE id = i.id AND w.status = 'active' THEN 1 ELSE 0 END) AS wish
FROM i
INNER JOIN r ON i.id = r.id AND r.status = 'active'
WHERE r.member_id = 1
你想为w中的每场比赛换一排吗?或者只是知道i.id,是否有活跃的记录?我假设第二个答案,所以你不需要ORDER BY - 它只适用于一个ID。而且由于你只是从i返回列,如果r中有多行,你只会得到重复的行。
如何发布您希望获得正确答案的内容?
答案 2 :(得分:1)
我应该把这个放在原来的问题中。这是从SQLYog返回的EXPLAIN
ID | SELECT_TYPE |表|类型| possible_keys |关键| key_len |裁判|行|额外|
1 | PRIMARY | r | ref | member_id,id | member_id | 3 | const | 3120 |使用where;使用临时;使用filesort
1 | PRIMARY | I | eq_ref | ID | ID | 8 | r.id | 1 |
2 | DEPENDENT SUBQUERY | w | index_subquery | id,status | id | 8 | func | 8 |使用where
答案 3 :(得分:1)
...
ORDER BY wish DESC
LIMIT 0,50
这似乎是一项巨大的开支。您按计算列“wish
”排序,该列无法从索引中受益。这会强制它使用 filesort (由EXPLAIN指示)输出,这意味着它将整个结果集写入磁盘并使用非常慢的磁盘I / O对其进行排序。
当您发布此类问题时,您不应期望人们猜测您是如何定义表和索引的。获得完整定义非常简单:
mysql> SHOW CREATE TABLE w;
mysql> SHOW CREATE TABLE i;
mysql> SHOW CREATE TABLE r;
然后将输出粘贴到您的问题中。
目前尚不清楚“wish
”列的目的是什么。 “IN
”谓词是一个布尔表达式,所以它总是导致0或1.但我猜你正在尝试使用“IN
”以期在没有做到的情况下完成连接加入。如果你描述你想要完成的事情会有所帮助。
试试这个:
SELECT i.*
FROM i
INNER JOIN r ON i.id=r.id
LEFT OUTER JOIN w ON i.id=w.id AND w.status='active'
WHERE r.member_id=1 AND r.status='active'
AND w.id IS NULL
LIMIT 0,50;
它使用了一个额外的外部联接,但根据我的EXPLAIN测试, 不会招致文件分发。
答案 4 :(得分:0)
你试过这个吗?
SELECT i.*, w.id as wish FROM i
LEFT OUTER JOIN w ON i.id = w.id
AND w.status = 'active'
WHERE i.id in (SELECT id FROM r WHERE r.member_id = 1 AND r.status = 'active')
ORDER BY wish DESC
LIMIT 0,50