SQL非唯一条件去重:cc_index表URL单条保留需求及性能问询
问题1:修改查询实现每个url仅保留符合条件的一行
假设你现有的查询是通过子查询找到每个url的最大length后关联原表,这种方式会在同一url存在多个最大length行时返回多行。可以用**窗口函数ROW_NUMBER()**来精准筛选符合要求的行,这是最简洁高效的方案:
SELECT * FROM ( SELECT *, -- 按url分组,先按length降序,再按date降序编号 ROW_NUMBER() OVER ( PARTITION BY url ORDER BY length DESC, date DESC ) AS row_num FROM cc_index ) filtered WHERE row_num = 1;
逻辑说明:
PARTITION BY url:将数据按url分组,每组单独处理ORDER BY length DESC, date DESC:组内先按length从大到小排序,length相同则按date从新到旧排序ROW_NUMBER():给每组的行分配唯一编号,排序最靠前的行编号为1,最终筛选出编号为1的行就是每个url的目标数据
如果你的数据库不支持窗口函数(比如旧版本MySQL),可以用关联子查询实现:
SELECT c.* FROM cc_index c INNER JOIN ( SELECT url, MAX(length) AS max_length, -- 先找到每个url的最大length,再在这些行里找最新的date MAX(date) AS max_date FROM cc_index WHERE (url, length) IN ( SELECT url, MAX(length) FROM cc_index GROUP BY url ) GROUP BY url ) t ON c.url = t.url AND c.length = t.max_length AND c.date = t.max_date;
问题2:无需关注date时,能否大幅提升查询性能?
通常可以提升性能,具体提升幅度取决于数据量和索引情况:
性能提升的原因:
- 减少排序开销:原本需要按
length DESC, date DESC双字段排序,现在仅需按length DESC单字段排序,排序计算量减少;如果用数据库特定函数(如MySQL的ANY_VALUE),甚至可以完全避免排序。 - 更高效的查询写法:以MySQL为例,直接用
GROUP BY结合MAX()和ANY_VALUE:
SELECT url, MAX(length) AS length, ANY_VALUE(date) AS date, ANY_VALUE(其他列名) AS 其他列名 FROM cc_index GROUP BY url;
这种写法不需要子查询和窗口函数的额外计算,直接分组取最大length,其他列取任意值,执行效率远高于窗口函数方案。
3. 索引优化空间更大:创建(url, length)的复合索引后,数据库可以直接通过索引快速定位每个url的最大length行,无需全表扫描,性能提升显著。
注意:
不同数据库对这类场景的优化语法不同,比如PostgreSQL可以用DISTINCT ON(同样高效):
SELECT DISTINCT ON (url) * FROM cc_index ORDER BY url, length DESC;
内容的提问来源于stack exchange,提问作者mbpaulus
相关产品推荐
相关产品推荐

