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