MYSQL 在按另一列排序的列中选择特定数量的重复值

标签 mysql sql optimization query-optimization greatest-n-per-group

SELECT notes.* FROM notes 
WHERE notes.id IN (
SELECT T1.id 
FROM notes as T1 
WHERE ( 
    SELECT COUNT(*)
    FROM notes as T2 
    WHERE T2.category_id = T1.category_id 
    AND T2.created_at > T1.created_at 
    AND T1.user_id = T2.user_id
) < N
) 
AND user_id = 2

此查询在按 created_at 排序的每个 category_id 中选择 N 行。 一切正常,直到:

1) 结果数量 > 50,因为性能下降是线性的或更糟:200 行即使有索引也需要 2.6 秒。

2) 结果中显示了几个相等的 created_at 值。在这种情况下,您将在类别中获得多于 N 行。

主要问题是如何优化此查询或编写另一个具有相同功能的查询?特定 user_id 的 1000 行所需性能为 0.5 秒。 第 2 点是可选的。性能是主要问题。 http://sqlfiddle.com/#!9/aa713f/3

解释:

1   PRIMARY notes   
NULL
ref PRIMARY,user_id user_id 4   const   654 100.00  
NULL

1   PRIMARY T1  
NULL
eq_ref  PRIMARY PRIMARY 4   admin_bt.notes.id   1   100.00  Using where 
3   DEPENDENT SUBQUERY  T2  
NULL
ref category_id,created_at,user_id,catcrbabusr  catcrbabusr 4   admin_bt.T1.category_id 1148    3.33    Using where; Using index    

最佳答案

我不确定我是否完全理解您的查询逻辑,但以下查询至少会产生相同的结果(而且肯定会用更少的时间):

这假定一个索引 (user_id, category_id,created_at)

SELECT x.* 
  FROM notes x
  JOIN 
     ( SELECT user_id
            , category_id
            , MAX(created_at) created_at
         FROM notes
        WHERE user_id IN(2)
        GROUP
           BY user_id
            , category_id
     ) y
    ON y.user_id = x.user_id
   AND y.category_id = x.category_id
   AND y.created_at = x.created_at;

这是您可能会喜欢的另一个想法...

SELECT id
     , created_at
     , user_id
     , category_id
  FROM 
     ( SELECT x.*
            , CASE WHEN @prev = category_id THEN @i:=@i+1 ELSE @i:=1 END i
            , @prev := category_id
         FROM notes x
            , (SELECT @prev:=null,@i:=0) vars
        WHERE user_id = 2
        ORDER  
           BY category_id
            , created_at
      ) n
  WHERE i <= 2;

关于MYSQL 在按另一列排序的列中选择特定数量的重复值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51684243/

相关文章:

php - mysql 上的内部连接只适用于一列

php - MySql ORDER By rand() 一行

mysql - 根据表内的值更新表

mysql - 组合键作为外键(sql)

mysql - 尝试选择最大列学年

mysql - 优化只读Mysql Slave

php - 如果此人存在则 MySQL 更新

sql - 如何在sql server中的一个存储过程中执行两个选择查询

java - 在java循环中节省内存和CPU

c# - .NET/C# 中的宽松异常是什么?