MySQL 对多列进行排序的重复问题
Duplication Issue with MySQL sorting on multiple columns
对于给定的唯一项目列表,在根据几列分批对它们进行排序后,我得到了重复的项目。
有 2 个表:
- item_popularity_tbl:
iid (UINT, PK) pplt (UTINYINT)
- item_cat_id_tbl:
iid (UINT, PK) cid (UTINYINT)
Where:
iid: item ID, unique values in the tables
cid: cat ID, values in the range (1, 15). Multiple items can have same cid.
pplt: popularity, vals in the range (1, 10). Multiple items can have same pplt.
给定项目 ID 列表,它们都是唯一的,我需要按 cid ASC 排序,然后按 pplt DESC 排序。
我使用下面的SQL(使用MySQL)代码来实现它:
# python code snippet
def db_get_items_sorted(conn, iid_list, offset, limit):
n1 = ','.join( ['%s'] * len(iid_list) )
#
sql_stmt = ("SELECT a.iid, a.cid, b.pplt "
"FROM pclg.item_cat_id_tbl AS a "
"INNER JOIN pclg.item_popularity_tbl AS b ON b.iid=a.iid "
"WHERE a.iid IN (%s) "
"ORDER BY a.cid ASC, "
"b.pplt DESC "
"LIMIT %s,%s") % (n1, offset, limit)
#
return conn.query(sql_stmt % tuple(iid_list))
我以 10 个为一组调用 db_get_items_sorted(...)。我使用 58 个项目(唯一)的输入 iid_list 对具有唯一 iid 的完全填充表进行了测试。对于每个调用,mysql returns 唯一的 10 个 iid,并按要求进行适当排序。但是当我连接批次以创建最后的 58 个项目时,我注意到列表中的几个项目 (iid) 是重复的(对于那些,返回的所有列都是相同的,基本上是完全重复的)。例如,48 个唯一行和 10 个重复行。
如果我用偏移量 0 和限制 58 调用 db_get_items_sorted(...),则没有 iid 重复项。但是,我需要小批量调用,因为我们可能会对数千个项目进行这种排序,然后继续。
问题是:如何实现跨批次的iid唯一性?
您可以使用 distinct 处理查询,因此删除重复项的是查询本身。
sql_stmt = ("SELECT DISTINCT a.iid, a.cid, b.pplt "
"FROM pclg.item_cat_id_tbl AS a "
"INNER JOIN pclg.item_popularity_tbl AS b ON b.iid=a.iid "
"WHERE a.iid IN (%s) "
"ORDER BY a.cid ASC, "
"b.pplt DESC "
"LIMIT %s,%s") % (n1, offset, limit)
我不喜欢使用 DISTINCT 来解决问题。我不确定为什么行重复首先发生,因此想解决这个问题。
下面是修复,在 ORDER BY 中使用具有唯一值的列 iid:
sql_stmt = ("SELECT a.iid, a.cid, b.pplt "
"FROM pclg.item_cat_id_tbl AS a "
"INNER JOIN pclg.item_popularity_tbl AS b ON b.iid=a.iid "
"WHERE a.iid IN (%s) "
"ORDER BY a.cid ASC, "
"b.pplt DESC, a.iid DESC "
"LIMIT %s,%s") % (n1, offset, limit)
长话短说:
当我们将 LIMIT 与 ORDER BY 一起使用并且 ORDER BY 中使用的列没有唯一值时,就会发生重复。
原因:
LIMIT returns 找到满足查询所需行数的那一刻。
当具有非唯一值的列与 ORDER BY 一起使用时,包含这些列的相同值的行不需要具有确定性排序。
因此,使用 LIMIT 并多次调用此例程(最终将它们连接起来以产生最终结果),mysql 是 运行 多次 ORDER BY 并且行的列具有相同的 val (在 ORDER BY 中使用)在这些调用中是非排序的——即它们的位置不是恒定的。 LIMIT M,N 然而 returns 来自 ORDER BY 结果的特定 (M, N) window 的行。
这导致最终的串联结果包含重复行。
参考:https://dev.mysql.com/doc/refman/5.7/en/limit-optimization.html
对于给定的唯一项目列表,在根据几列分批对它们进行排序后,我得到了重复的项目。
有 2 个表:
- item_popularity_tbl:
iid (UINT, PK) pplt (UTINYINT)
- item_cat_id_tbl:
iid (UINT, PK) cid (UTINYINT)
Where:
iid: item ID, unique values in the tables
cid: cat ID, values in the range (1, 15). Multiple items can have same cid.
pplt: popularity, vals in the range (1, 10). Multiple items can have same pplt.
给定项目 ID 列表,它们都是唯一的,我需要按 cid ASC 排序,然后按 pplt DESC 排序。
我使用下面的SQL(使用MySQL)代码来实现它:
# python code snippet
def db_get_items_sorted(conn, iid_list, offset, limit):
n1 = ','.join( ['%s'] * len(iid_list) )
#
sql_stmt = ("SELECT a.iid, a.cid, b.pplt "
"FROM pclg.item_cat_id_tbl AS a "
"INNER JOIN pclg.item_popularity_tbl AS b ON b.iid=a.iid "
"WHERE a.iid IN (%s) "
"ORDER BY a.cid ASC, "
"b.pplt DESC "
"LIMIT %s,%s") % (n1, offset, limit)
#
return conn.query(sql_stmt % tuple(iid_list))
我以 10 个为一组调用 db_get_items_sorted(...)。我使用 58 个项目(唯一)的输入 iid_list 对具有唯一 iid 的完全填充表进行了测试。对于每个调用,mysql returns 唯一的 10 个 iid,并按要求进行适当排序。但是当我连接批次以创建最后的 58 个项目时,我注意到列表中的几个项目 (iid) 是重复的(对于那些,返回的所有列都是相同的,基本上是完全重复的)。例如,48 个唯一行和 10 个重复行。
如果我用偏移量 0 和限制 58 调用 db_get_items_sorted(...),则没有 iid 重复项。但是,我需要小批量调用,因为我们可能会对数千个项目进行这种排序,然后继续。
问题是:如何实现跨批次的iid唯一性?
您可以使用 distinct 处理查询,因此删除重复项的是查询本身。
sql_stmt = ("SELECT DISTINCT a.iid, a.cid, b.pplt "
"FROM pclg.item_cat_id_tbl AS a "
"INNER JOIN pclg.item_popularity_tbl AS b ON b.iid=a.iid "
"WHERE a.iid IN (%s) "
"ORDER BY a.cid ASC, "
"b.pplt DESC "
"LIMIT %s,%s") % (n1, offset, limit)
我不喜欢使用 DISTINCT 来解决问题。我不确定为什么行重复首先发生,因此想解决这个问题。
下面是修复,在 ORDER BY 中使用具有唯一值的列 iid:
sql_stmt = ("SELECT a.iid, a.cid, b.pplt "
"FROM pclg.item_cat_id_tbl AS a "
"INNER JOIN pclg.item_popularity_tbl AS b ON b.iid=a.iid "
"WHERE a.iid IN (%s) "
"ORDER BY a.cid ASC, "
"b.pplt DESC, a.iid DESC "
"LIMIT %s,%s") % (n1, offset, limit)
长话短说: 当我们将 LIMIT 与 ORDER BY 一起使用并且 ORDER BY 中使用的列没有唯一值时,就会发生重复。
原因:
LIMIT returns 找到满足查询所需行数的那一刻。
当具有非唯一值的列与 ORDER BY 一起使用时,包含这些列的相同值的行不需要具有确定性排序。
因此,使用 LIMIT 并多次调用此例程(最终将它们连接起来以产生最终结果),mysql 是 运行 多次 ORDER BY 并且行的列具有相同的 val (在 ORDER BY 中使用)在这些调用中是非排序的——即它们的位置不是恒定的。 LIMIT M,N 然而 returns 来自 ORDER BY 结果的特定 (M, N) window 的行。
这导致最终的串联结果包含重复行。
参考:https://dev.mysql.com/doc/refman/5.7/en/limit-optimization.html