我的目标
我试图检索多个随机行,其中只包含唯一的用户ID,但类型列是随机的 – 类型只能是0或1.有问题的表在任何给定时间都包含少于1,000行.
我的桌子
CREATE TABLE tbl_message_queue (
userid bigint(20) NOT NULL,
messageid varchar(20) NOT NULL,
`type` int(1) NOT NULL,
PRIMARY KEY (userid,messageid,`type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
样本数据
userid | messageid | type
---------------------------------------------------
4353453 | 518423942 | 0
4353453 | 518423942 | 1
2342934 | 748475435 | 0
2342934 | 748475435 | 1
7657529 | 821516543 | 0
7657529 | 821516543 | 1
0823546 | 932843285 | 0
0823546 | 932843285 | 1
要排除什么
使用ORDER BY RAND()是不可行的,因为在任何给定时刻应用程序都会执行至少18,000种这类查询并导致高负载.使用SELECT DISTINCT或GROUP BY(显然)更有效,并且总是选择唯一的用户ID,但是类型总是等于0且具有可接受的负载.
常见的方法是创建一个id列,但我只是在寻找另一种方法.组主键不能根据需要进行更改并深入集成到我们的应用程序中,但每列的结构都可以更改.
谢谢.
最佳答案 我对你的问题的理解是,对于每个用户ID,你有两个条目,但是想要随机提取一个.
要实现这一点,您应该为每个唯一的用户ID生成0到1之间的随机值,然后使用起始列表加入此列表:
SELECT a.* FROM tbl_message_queue AS a
JOIN ( SELECT userid, FLOOR(2*RAND()) AS type
FROM tbl_message_queue GROUP BY userid ) AS b
ON ( a.userid = b.userid AND a.type = b.type );
但是如果ORDER BY RAND()不适合你,也许我们应该妥协.
在上面的序列中,任何两个用户ID将是不相关的 – 即,用户A获得类型0的事实不会告诉您用户B将会出现什么.
根据用例,可以通过两个查询获得较少随机(但“明显随机”)的序列:
SELECT @X := FLOOR(2*RAND()), @Y := POW(2,FLOOR(2+14*RAND()))-1;
SELECT * FROM tbl_message_queue WHERE (((userid % @Y) & 1) XOR type XOR @X);
通过这种方式,您可以获得似乎随机抽取的内容.真正发生的是用户标识是相关的,你只能进行几十次不同的提取.但是只使用简单的运算符,而且没有JOIN,这个查询非常快.