Mysql 三表关系顺序正确,但值为false
我有那些桌子Mysql 三表关系顺序正确,但值为false,mysql,sql,left-join,inner-join,query-performance,Mysql,Sql,Left Join,Inner Join,Query Performance,我有那些桌子 table1 | id | name | | 1 | axe | | 2 | bow | | 3 | car | | 4 | dart | table2 table3 | t1_id | number | | t1_id | letter | | 1
table1
| id | name |
| 1 | axe |
| 2 | bow |
| 3 | car |
| 4 | dart |
table2 table3
| t1_id | number | | t1_id | letter |
| 1 | 5 | | 1 | a |
| 1 | 6 | | 1 | b |
| 1 | 2 | | 1 | c |
| 2 | 2 | | 2 | a |
| 2 | 2 | | 2 | c |
| 2 | 3 | | 2 | r |
| 3 | 8 | | 3 | y |
| 3 | 3 | | 3 | i |
| 3 | 1 | | 3 | a |
| 4 | 8 | | 4 | a |
| 4 | 9 | | 4 | b |
| 4 | 10 | | 4 | c |
并且表1(id)与表2(t1\U id)、表3(t1\U id)链接
我运行它,按照最高字母数匹配,然后按照最高平均数匹配,得到这个正确的结果
一切正常
但是当我想检查查询是否有任何问题时,我决定检查字母计数和平均数字,所以我使用了这个查询
SELECT
t1.id,
t1.name,
COUNT(t3.letter) AS letter_count,
AVG(t2.number) AS avg_number
FROM
table1 t1
INNER JOIN
table2 t2
ON t2.t1_id = t1.id
LEFT JOIN
table3 t3
ON t3.t1_id = t1.id
AND t3.letter IN ('a', 'b', 'c')
GROUP BY
t1.id
ORDER BY
letter_count DESC,
avg_number DESC
我所期望的结果是
| id | name | letter_count | avg_number |
| 4 | dart | 3 | 9 |
| 1 | axe | 3 | 4.3333333333 |
| 2 | bow | 2 | 2.3333333333 |
| 3 | car | 1 | 4 |
但我得到的结果是
令我惊讶的是字母计数的乘法行可以通过派生查询解决,但我不想选择字母计数或数字平均值,我只想按它们排序
按顺序保持查询的原样只会影响查询性能吗?或者,即使我不需要选择数据值,我也应该使用派生查询,因为顺序是正确的,或者派生查询在大型表中会更快吗?这将检索您需要的:
SELECT a.id, a.name, count(a.letter) letter_count, avg(a.number) avg_number
FROM( SELECT
t1.id,
t1.name,
t3.letter,
t2.number--,
FROM
table1 t1
INNER JOIN
table2 t2
ON t2.t1_id = t1.id
INNER JOIN
table3 t3
ON t3.t1_id = t1.id
AND t3.letter IN ('a', 'b', 'c')
GROUP BY
t1.id, t1.name, t3.letter, t2.number) a GROUP BY id, a.name
ORDER BY
letter_count DESC,
avg_number DESC
你在这里真的问了两个问题:
orderby
子句是否影响查询性能ORDER BY
子句,都需要计算表达式,以便确定顺序。在第一个示例中,您需要指定表达式,因为这些列不包含在SELECT
语句中
但是,在第二次查询中,您选择了要排序依据的列,并且由于整个查询处理后会对order by
进行计算,因此您只需在order by
子句中使用列别名,而无需再次执行该函数
如果您对SELECT
子句中存在的表达式进行排序,一些RDBMS查询优化程序会将ORDER BY
语句中的表达式转换为使用列别名
您这样做是正确的,但是,由于响应中存在重复项,因此您的字母计数表达式不是最新的
只需将COUNT
表达式更改为使用distinct子句仅对唯一值进行计数
COUNT(DICTINCT t3.letter)
这使您的原始查询现在看起来如下所示:
SELECT
t1.id,
t1.name
FROM
table1 t1
INNER JOIN
table2 t2
ON t2.t1_id = t1.id
LEFT JOIN
table3 t3
ON t3.t1_id = t1.id
AND t3.letter IN ('a', 'b', 'c')
GROUP BY
t1.id
ORDER BY
COUNT(DICTINCT t3.letter) DESC,
AVG(t2.number) DESC
我对其进行了重构,但在第二次查询结果中删除了group by语句,并在select中包含
t3.letter
和t2.number
,这应该可以突出显示为什么原始查询中的count返回的值与您期望的值不同。在一个大的记录集上,此值错误可能会导致与预期不同的顺序。如果我没有添加独特的
,并在将来保留数百万条记录,那么会发生什么呢?我应该用派生查询修复重复的响应,还是不需要在“仅排序”的情况下修复它?这是一个足够简单的查询,我怀疑使用子查询或派生查询将使该查询复杂化,并使其在更大的记录集上运行得更慢。但这将取决于您的派生查询。如果您对此查询的性能不满意,请进行派生查询并比较执行时间,我们可以从理论上讲,但实际执行计划和时间将受到特定查询实现、模式和服务器资源的极大影响
SELECT a.id, a.name, count(a.letter) letter_count, avg(a.number) avg_number
FROM( SELECT
t1.id,
t1.name,
t3.letter,
t2.number--,
FROM
table1 t1
INNER JOIN
table2 t2
ON t2.t1_id = t1.id
INNER JOIN
table3 t3
ON t3.t1_id = t1.id
AND t3.letter IN ('a', 'b', 'c')
GROUP BY
t1.id, t1.name, t3.letter, t2.number) a GROUP BY id, a.name
ORDER BY
letter_count DESC,
avg_number DESC
COUNT(DICTINCT t3.letter)
SELECT
t1.id,
t1.name
FROM
table1 t1
INNER JOIN
table2 t2
ON t2.t1_id = t1.id
LEFT JOIN
table3 t3
ON t3.t1_id = t1.id
AND t3.letter IN ('a', 'b', 'c')
GROUP BY
t1.id
ORDER BY
COUNT(DICTINCT t3.letter) DESC,
AVG(t2.number) DESC