Mysql,获取多列索引中特定行之前的行

标签 mysql sql indexing sql-order-by multiple-columns

假设我有这张高分表:

id : primary key
username : string
score : int

用户名和分数本身可以重复,只有id是每个人唯一的。我还有一个快速获得高分的索引:

UNIQUE scores ( score, username, id )

我怎样才能得到给定人下面的行? “下方”是指它们在此索引中的给定行之前。

例如for ( 77, 'name7', 70 ) in format ( score, username, id ) 我想检索:

77, 'name7', 41
77, 'name5', 77
77, 'name5', 21
50, 'name9', 99

但不是

77, 'name8', 88 or
77, 'name7', 82 or
80, 'name2', 34 ...

最佳答案

这是获取结果的一种方法:

SELECT t.score
     , t.username
     , t.id
  FROM scores t
 WHERE ( t.score < 77 ) 
    OR ( t.score = 77 AND t.username < 'name7' )
    OR ( t.score = 77 AND t.username = 'name7' AND t.id < 70 )
 ORDER
    BY t.score DESC
     , t.username DESC
     , t.id DESC

(注意:ORDER BY 子句可以帮助 MySQL 决定使用索引来避免“Using filesort”操作。您的索引是查询的“覆盖”索引,因此我们会希望在 EXPLAIN 输出中看到“Using index”。)


我进行了快速测试,在我的环境中,这确实执行了索引范围扫描并避免了排序操作。

解释输出

id  select_type table type  possible_keys      key        rows Extra                     
--  ----------- ----- ----- ------------------ ---------- ---- --------------------------
 1  SIMPLE      t     range PRIMARY,scores_UX1 scores_UX1    3 Using where; Using index 

(如果您不需要返回满足条件的所有行,您可能需要向该查询添加一个 LIMIT n。)

如果您有行的唯一 ID,则可以通过连接避免指定表中的值。鉴于您问题中的数据:

这里我们使用对同一个表的第二个引用来获取 id=70 的行,然后进行连接以获取所有“较低”的行。

SELECT t.score
     , t.username
     , t.id
  FROM scores k
  JOIN scores t
    ON ( t.score < k.score ) 
    OR ( t.score = k.score AND t.username < k.username )
    OR ( t.score = k.score AND t.username = k.username AND t.id < k.id )
 WHERE k.id = 70
 ORDER
    BY t.score DESC
     , t.username DESC
     , t.id DESC
 LIMIT 1000

此查询的 EXPLAIN 还显示 MySQL 使用覆盖索引并避免排序操作:

id select_type table type  possible_keys      key         rows Extra
-- ----------- ----- ----- ------------------ ----------  ---- ------------------------
 1 SIMPLE      k     const PRIMARY,scores_UX1 PRIMARY       1
 1 SIMPLE      t     range PRIMARY,scores_UX1 scores_UX1    3  Using where; Using index

关于Mysql,获取多列索引中特定行之前的行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18196971/

相关文章:

c# - 在SQL中删除短于24小时的 token

java - 在 java 存储过程中创建 java.sql.blob 实例

java - 如何从jsp页面将日期插入mysql数据库?

mysql - 使用 SUM 计算,查询不起作用?

MySQL 定位和反向查询

sql - 以最优化的方式从sql server表中获取记录数

sql - 两列上的 group by 索引

mysql - 有人可以推荐一个关于 MySQL 索引的好教程,特别是在连接期间在 order by 子句中使用时吗?

使用 Straight_Join 的 MySQL 查询成本更低,但执行时间更长

mysql - 无法在 Mysql Docker 容器内安装 mysql2 gem : Failed to build gem native extension