MySQL在多列上排序的重复问题

时间:2017-02-15 19:46:35

标签: mysql innodb percona

对于给定的唯一项目列表,在基于几列批量对它们进行排序后,我会得到重复的项目。

有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测试了这个,对照具有唯一iids的完全填充的表。对于每个调用,mysql根据请求返回具有适当排序的唯一10个iids。但是当我连接批次以创建最后58个项目时,我注意到列表中的几个项目(iid)是重复的(对于那些,返回的所有列都是相同的,基本上完全重复)。例如,48个唯一行和10个重复行。

如果我使用偏移0和限制58调用db_get_items_sorted(...),则没有iid重复。但是,我需要小批量打电话,因为我们可能会对未来几千个项目进行排序。

问题是:如何跨批次实现iid唯一性?

2 个答案:

答案 0 :(得分:1)

您可以使用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)

答案 1 :(得分:0)

我不想使用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)

TL; DR: 由于我们使用LIMIT和ORDER BY并且ORDER BY中使用的列没有唯一的val,因此发生了重复。

原因:

  • LIMIT会在找到满足查询所需的行数时返回。

  • 当具有非唯一值的列与ORDER BY一起使用时,保持这些列的相同val的行不需要具有确定性排序。

因此,使用LIMIT并多次调用此例程(最终连接它们以产生最终结果),mysql运行ORDER BY几次,并且具有相同val的行(在ORDER BY中使用)是非有序的这些电话 - 即他们的立场不一致。然而,LIMIT M,N返回ORDER BY结果的特定(M,N)窗口中的行。

这导致最终的连接结果保留重复的行。

参考:https://dev.mysql.com/doc/refman/5.7/en/limit-optimization.html