Sql 连接与子查询
我是一个老派的MySQL用户,总是喜欢Sql 连接与子查询,sql,mysql,subquery,join,Sql,Mysql,Subquery,Join,我是一个老派的MySQL用户,总是喜欢JOIN而不是sub-query。但是现在每个人都使用子查询,我讨厌它;我不知道为什么 我缺乏理论知识来判断是否存在差异。子查询是否与连接一样好,因此无需担心?子查询是解决“从a获取事实,以从B获取事实为条件”形式问题的逻辑正确方法。在这种情况下,在子查询中使用B比使用联接更有逻辑意义。从实际意义上讲,它也更安全,因为你不必因为与B的多次匹配而对从a获得重复的事实持谨慎态度 然而,实际上,答案通常取决于性能。一些优化程序在给定联接与子查询时会吸取柠檬,而另一
JOIN
而不是sub-query。但是现在每个人都使用子查询,我讨厌它;我不知道为什么
我缺乏理论知识来判断是否存在差异。子查询是否与连接一样好,因此无需担心?子查询是解决“从a获取事实,以从B获取事实为条件”形式问题的逻辑正确方法。在这种情况下,在子查询中使用B比使用联接更有逻辑意义。从实际意义上讲,它也更安全,因为你不必因为与B的多次匹配而对从a获得重复的事实持谨慎态度 然而,实际上,答案通常取决于性能。一些优化程序在给定联接与子查询时会吸取柠檬,而另一些优化程序则会以另一种方式吸取柠檬,这是特定于优化程序、特定于DBMS版本和特定于查询的
从历史上看,显式连接通常是成功的,因此公认的观点是连接更好,但乐观主义者总是越来越好,因此我更倾向于以逻辑一致的方式首先编写查询,如果性能限制允许,则重新构造。子查询通常用于将单行作为原子值返回,尽管它们可能用于将值与多行中的IN关键字进行比较。它们几乎可以出现在SQL语句中任何有意义的点上,包括目标列表、WHERE子句等等。一个简单的子查询可以用作搜索条件。例如,在一对表之间:
SELECT title
FROM books
WHERE author_id = (
SELECT id
FROM authors
WHERE last_name = 'Bar' AND first_name = 'Foo'
);
请注意,对子查询的结果使用普通值运算符只需要返回一个字段。如果您对检查一组其他值中是否存在单个值感兴趣,请使用:
SELECT title
FROM books
WHERE author_id IN (
SELECT id FROM authors WHERE last_name ~ '^[A-E]'
);
这显然不同于左连接,在左连接中,即使连接条件在表B中找不到任何匹配的记录,也只想连接表a和表B中的内容,等等
如果您只是担心速度,那么您必须检查您的数据库并编写一个好的查询,看看性能是否有显著差异。在大多数情况下,
JOIN
s比子查询快,而且子查询很少更快
在JOIN
s中,RDBMS可以创建一个更适合您的查询的执行计划,并且可以预测应该加载哪些数据以进行处理并节省时间,这与子查询不同,子查询将运行所有查询并加载其所有数据以进行处理
子查询的好处是它们比
JOIN
s更具可读性:这就是为什么大多数新SQL用户更喜欢它们;这是最简单的方法;但是说到性能,连接在大多数情况下都会更好,即使它们也不难阅读。使用EXPLAIN查看数据库如何对数据执行查询。这个答案中有一个巨大的“视情况而定”
PostgreSQL可以将子查询重写为联接,或者在认为其中一个比另一个快时将联接重写为子查询。这完全取决于数据、索引、相关性、数据量、查询等。首先,要比较这两种情况,您应该将查询与子查询区分开来:
对于第二个类比较没有意义,因为这些查询不能使用连接重写,在这些情况下,子查询是执行所需任务的自然方式,您不应歧视它们。在旧Mambo CMS的非常大的数据库上运行:
SELECT id, alias
FROM
mos_categories
WHERE
id IN (
SELECT
DISTINCT catid
FROM mos_content
);
0秒
SELECT
DISTINCT mos_content.catid,
mos_categories.alias
FROM
mos_content, mos_categories
WHERE
mos_content.catid = mos_categories.id;
约3秒
解释表明,他们检查的行数完全相同,但一行需要3秒钟,一行几乎是即时的。这个故事的寓意是什么?如果性能很重要(什么时候不是?),请尝试多种方法,看看哪种方法最快
而且
SELECT
DISTINCT mos_categories.id,
mos_categories.alias
FROM
mos_content, mos_categories
WHERE
mos_content.catid = mos_categories.id;
0秒
SELECT
DISTINCT mos_content.catid,
mos_categories.alias
FROM
mos_content, mos_categories
WHERE
mos_content.catid = mos_categories.id;
同样,相同的结果,相同数量的行被检查。我的猜测是,DISTINCT mos_content.catid比DISTINCT mos_categories.id需要更长的时间来计算。
许多包含子查询的Transact-SQL语句也可以表示为联接。其他问题只能通过子查询提出。在Transact-SQL中,包含子查询的语句与不包含子查询的语义等效版本之间通常没有性能差异。但是,在某些必须检查存在性的情况下,联接会产生更好的性能。否则,必须为外部查询的每个结果处理嵌套查询,以确保消除重复项。在这种情况下,联接方法将产生更好的结果
所以如果你需要像
select * from t1 where exists select * from t2 where t2.parent=t1.id
尝试改用join。在其他情况下,这没有什么区别
我说:为子查询创建函数可以消除clutter问题,并允许您实现子查询的附加逻辑。因此,我建议尽可能为子查询创建函数
代码混乱是一个大问题,业界一直在努力避免它
+----+--------------------+----------+--------+-----------------------------------------------------+--------------+---------+-------------------------------------------------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+----------+--------+-----------------------------------------------------+--------------+---------+-------------------------------------------------+------+--------------------------+
| 1 | PRIMARY | vrl | index | PRIMARY | moved_date | 8 | NULL | 200 | Using where |
| 1 | PRIMARY | l | eq_ref | PRIMARY,status,ispublic,idx_lookup,is_public_status | PRIMARY | 4 | ranker.vrl.list_id | 1 | Using where |
| 1 | PRIMARY | vrlih | eq_ref | PRIMARY | PRIMARY | 9 | ranker.vrl.list_id,ranker.vrl.ontology_id,const | 1 | Using where |
| 1 | PRIMARY | lbs | eq_ref | PRIMARY,idx_list_burial_state,burial_score | PRIMARY | 4 | ranker.vrl.list_id | 1 | Using where |
| 4 | DEPENDENT SUBQUERY | list_tag | ref | list_tag_key,list_id,tag_id | list_tag_key | 9 | ranker.l.list_id,const | 1 | Using where; Using index |
| 3 | DEPENDENT SUBQUERY | list_tag | ref | list_tag_key,list_id,tag_id | list_tag_key | 9 | ranker.l.list_id,const | 1 | Using where; Using index |
| 2 | DEPENDENT SUBQUERY | list_tag | ref | list_tag_key,list_id,tag_id | list_tag_key | 9 | ranker.l.list_id,const | 1 | Using where; Using index |
+----+--------------------+----------+--------+-----------------------------------------------------+--------------+---------+-------------------------------------------------+------+--------------------------+
EXPLAIN SELECT vrl.list_id,vrl.ontology_id,vrl.position,l.name AS list_name, vrlih.position AS previous_position, vrl.moved_date
FROM `vote-ranked-listory` vrl
INNER JOIN lists l ON l.list_id = vrl.list_id
INNER JOIN `vote-ranked-list-item-history` vrlih ON vrl.list_id = vrlih.list_id AND vrl.ontology_id=vrlih.ontology_id AND vrlih.type='PREVIOUS_POSITION'
INNER JOIN list_burial_state lbs ON lbs.list_id = vrl.list_id AND lbs.burial_score < 0.5
LEFT JOIN list_tag lt1 ON lt1.list_id = vrl.list_id AND lt1.tag_id = 43
LEFT JOIN list_tag lt2 ON lt2.list_id = vrl.list_id AND lt2.tag_id = 55
INNER JOIN list_tag lt3 ON lt3.list_id = vrl.list_id AND lt3.tag_id = 246403
WHERE vrl.position <= 15 AND l.status='ACTIVE' AND l.is_public=1 AND vrl.ontology_id < 1000000000
AND lt1.list_id IS NULL AND lt2.tag_id IS NULL
ORDER BY vrl.moved_date DESC LIMIT 200;
+----+-------------+-------+--------+-----------------------------------------------------+--------------+---------+---------------------------------------------+------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+-----------------------------------------------------+--------------+---------+---------------------------------------------+------+----------------------------------------------+
| 1 | SIMPLE | lt3 | ref | list_tag_key,list_id,tag_id | tag_id | 5 | const | 2386 | Using where; Using temporary; Using filesort |
| 1 | SIMPLE | l | eq_ref | PRIMARY,status,ispublic,idx_lookup,is_public_status | PRIMARY | 4 | ranker.lt3.list_id | 1 | Using where |
| 1 | SIMPLE | vrlih | ref | PRIMARY | PRIMARY | 4 | ranker.lt3.list_id | 103 | Using where |
| 1 | SIMPLE | vrl | ref | PRIMARY | PRIMARY | 8 | ranker.lt3.list_id,ranker.vrlih.ontology_id | 65 | Using where |
| 1 | SIMPLE | lt1 | ref | list_tag_key,list_id,tag_id | list_tag_key | 9 | ranker.lt3.list_id,const | 1 | Using where; Using index; Not exists |
| 1 | SIMPLE | lbs | eq_ref | PRIMARY,idx_list_burial_state,burial_score | PRIMARY | 4 | ranker.vrl.list_id | 1 | Using where |
| 1 | SIMPLE | lt2 | ref | list_tag_key,list_id,tag_id | list_tag_key | 9 | ranker.lt3.list_id,const | 1 | Using where; Using index |
+----+-------------+-------+--------+-----------------------------------------------------+--------------+---------+---------------------------------------------+------+----------------------------------------------+
AND (SELECT list_id FROM list_tag WHERE list_id=l.list_id AND tag_id=246403) IS NOT NULL
INNER JOIN list_tag lt3 ON lt3.list_id = vrl.list_id AND lt3.tag_id = 246403
SELECT titles, price
FROM Books, Orders
WHERE price =
(SELECT MIN(price)
FROM Orders) AND (Books.ID=Orders.ID);
SELECT MIN(price)
FROM Orders;
-----------------
2.99
SELECT titles, price
FROM Books b
INNER JOIN Orders o
ON b.ID = o.ID
WHERE o.price = 2.99;
+------+--------+------+--------+
| sID | sName | GPA | sizeHS |
+------+--------+------+--------+
| 123 | Amy | 3.9 | 1000 |
| 234 | Bob | 3.6 | 1500 |
| 345 | Craig | 3.5 | 500 |
| 456 | Doris | 3.9 | 1000 |
| 567 | Edward | 2.9 | 2000 |
| 678 | Fay | 3.8 | 200 |
| 789 | Gary | 3.4 | 800 |
| 987 | Helen | 3.7 | 800 |
| 876 | Irene | 3.9 | 400 |
| 765 | Jay | 2.9 | 1500 |
| 654 | Amy | 3.9 | 1000 |
| 543 | Craig | 3.4 | 2000 |
+------+--------+------+--------+
+------+----------+----------------+----------+
| sID | cName | major | decision |
+------+----------+----------------+----------+
| 123 | Stanford | CS | Y |
| 123 | Stanford | EE | N |
| 123 | Berkeley | CS | Y |
| 123 | Cornell | EE | Y |
| 234 | Berkeley | biology | N |
| 345 | MIT | bioengineering | Y |
| 345 | Cornell | bioengineering | N |
| 345 | Cornell | CS | Y |
| 345 | Cornell | EE | N |
| 678 | Stanford | history | Y |
| 987 | Stanford | CS | Y |
| 987 | Berkeley | CS | Y |
| 876 | Stanford | CS | N |
| 876 | MIT | biology | Y |
| 876 | MIT | marine biology | N |
| 765 | Stanford | history | Y |
| 765 | Cornell | history | N |
| 765 | Cornell | psychology | Y |
| 543 | MIT | CS | N |
+------+----------+----------------+----------+
select GPA from Student where sID in (select sID from Apply where major = 'CS');
+------+
| GPA |
+------+
| 3.9 |
| 3.5 |
| 3.7 |
| 3.9 |
| 3.4 |
+------+
select avg(GPA) from Student where sID in (select sID from Apply where major = 'CS');
+--------------------+
| avg(GPA) |
+--------------------+
| 3.6800000000000006 |
+--------------------+
select GPA from Student, Apply where Student.sID = Apply.sID and Apply.major = 'CS';
+------+
| GPA |
+------+
| 3.9 |
| 3.9 |
| 3.5 |
| 3.7 |
| 3.7 |
| 3.9 |
| 3.4 |
+------+
select avg(GPA) from Student, Apply where Student.sID = Apply.sID and Apply.major = 'CS';
+-------------------+
| avg(GPA) |
+-------------------+
| 3.714285714285714 |
+-------------------+
SELECT *
FROM crv.workorder_details wd
inner join crv.workorder wr on wr.workorder_id = wd.workorder_id;
select *
from crv.workorder_details
where workorder_id in (select workorder_id from crv.workorder)
SELECT moo, (SELECT roger FROM wilco WHERE moo = me) AS bar FROM foo
SELECT moo FROM foo WHERE bar = (SELECT roger FROM wilco WHERE moo = me)
SELECT moo, bar
FROM foo
LEFT JOIN (
SELECT MIN(bar), me FROM wilco GROUP BY me
) ON moo = me
SELECT VARIANCE(moo)
FROM (
SELECT moo, CONCAT(roger, wilco) AS bar
FROM foo
HAVING bar LIKE 'SpaceQ%'
) AS temp_foo
GROUP BY moo
select id,name from table1 a
join table2 b on a.name=b.name
where id='123'
Try,
select id,name from table1 a
join table2 b on a.name=b.name and a.id='123'