You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何高效查找SQL中包含子串的重复歌曲标题?

高效查找歌曲重复标题方案

问题分析

你需要查找两类重复记录:标题完全相同,或一个标题是另一个的前缀子串。之前使用子查询+LIKE/SUBSTRING的方式性能差,本质是逐行执行子查询带来了O(n²)的时间复杂度,数据量增大后耗时剧增。

优化方案

核心思路是利用索引减少扫描范围,通过自连接替代子查询,避免逐行统计。

1. 先创建标题索引

首先给songs表的title字段添加索引,这是所有优化的基础:

CREATE INDEX idx_songs_title ON songs(title);

2. Rails Scope实现

以下是两种高效的Scope写法:

写法一:单自连接语句

通过一次自连接覆盖所有重复场景,最后去重:

scope :duplicate_titles, -> {
  joins(
    "JOIN songs s2 
     ON (songs.title = s2.title AND songs.id != s2.id)
     OR (s2.title LIKE CONCAT(songs.title, '%') AND songs.id != s2.id)
     OR (songs.title LIKE CONCAT(s2.title, '%') AND songs.id != s2.id)"
  )
  .distinct
}
写法二:拆分场景合并结果

将完全重复、前缀重复、被前缀重复三个场景拆分,再通过UNION合并,逻辑更清晰:

scope :duplicate_titles, -> {
  # 匹配完全重复的记录
  exact_dupes = where(title: select(:title).group(:title).having("COUNT(*) > 1"))
  # 匹配当前标题是其他标题前缀的记录
  prefix_dupes = joins("JOIN songs s2 ON s2.title LIKE CONCAT(songs.title, '%') AND songs.id != s2.id")
  # 匹配当前标题包含其他标题前缀的记录
  reverse_prefix_dupes = joins("JOIN songs s2 ON songs.title LIKE CONCAT(s2.title, '%') AND songs.id != s2.id")

  # 合并结果并去重
  from("(#{exact_dupes.union(prefix_dupes).union(reverse_prefix_dupes).to_sql}) AS songs")
}

效果说明

针对你的示例数据,上述两种写法都会返回id为1、2、4、5的记录,满足需求。加上索引后,查询速度会从秒级降至毫秒级,和原基础查询耗时接近。

内容的提问来源于stack exchange,提问作者Mirror318

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 22:42:52