After mysql is grouped, take the first data of each group

Before mysql 5.7 (excluding 5.7)

select * from (select a.* from template_detail a
               where a.template_id in (3, 4)
              order by a.id desc) tt
group by tt.template_id;

But before mysql 5.7 (including 5.7), such queries will find that order by is invalid

It is because mysql 5.7 introduced derived_merge 

What is derived_merge?
derived_merge refers to a query optimization technology that merges derived tables into external queries to improve the efficiency of data retrieval. This feature was introduced in MySQL 5.7, and can be viewed/opened/closed through the following SQL statements.

Although the above sounds awesome, the actual situation is that this new feature is not very popular and it is easy to cause errors.

The following functions can be used in subqueries to turn off this feature:

Merging can be disabled by using any merge-preventing construct in the subquery, although the effect of these constructs on the materialization is not clear. The constructs that prevent merging are the same for derived table and view references:

  1.    aggregate functions ( SUM() , MIN() , MAX() , COUNT() , etc.)
  2.    DISTINCT
  3.    GROUP BY
  4.    HAVING
  5.    LIMIT
  6.    UNION or UNION ALL
  7.    subquery in select list
  8.    assign to user variable
  9.    Quote literal values ​​only (in this case, no underlying table)

So the more common implementation method of mysql5.7 is:

select * from (select a.* from template_detail a
               where a.template_id in (3, 4)
              order by a.id desc limit 10000) tt
group by tt.template_id;

This one is also the most recommended on the Internet, but I personally feel that the limitations are too large, and I don’t mind using it in actual combat

Recommended way of writing:

select * from (select distinct(a.id) tid, a.* from template_detail a
               where a.template_id in (3, 4)
              order by a.id desc) tt
group by tt.template_id;

After adding distinct(a.id) tid, the result is correct. The reason is that order by is used in the temporary table (derived table) and to make it effective, three conditions must be met:

  1. Outer queries prohibit grouping or aggregation
  2. The outer query does not specify having, HAVING, order by
  3. The external query uses derived tables or views as the only source specified in the from clause

If these three conditions are not met, order by will be ignored.

Once the external table uses group by, the temporary table (derived table) will not perform the filesort operation (that is, the order by will be ignored), so I added (distinct(a.id)) to the temporary table.
After adding it, it is equivalent to turning off this feature, so it will take effect.

 Or this is more efficient:

SELECT bb.`detail`, bb.`id`,bb.`template_id` 
from `template_detail` bb 
		INNER JOIN 
		( 
		    SELECT MAX(`id`) id, `template_id` 
		    from `template_detail` GROUP BY `template_id` 
		) as tb on bb.`id` = tb.id

Guess you like

Origin blog.csdn.net/sunyanchun/article/details/128447126