我的目标
我正在尝试检索仅包含唯一userid
的多个随机行,但type
列是随机的 - type
只能是0
或{{1 }}。有问题的表在任何给定时间都包含少于1,000行。
我的表
1
示例数据
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
是不可行的,因为在任何给定时刻应用程序都会执行至少18,000种这类查询并导致高负载。使用ORDER BY RAND()
或SELECT DISTINCT
(显然)效率更高,并且始终会选择唯一的GROUP BY
,但userid
将始终等于type
且负载可接受。
常用方法是创建0
列,但我正在寻找另一种方式 。组主键不能根据需要进行更改并深入集成到我们的应用程序中,但每列的结构都可以更改。
感谢。
答案 0 :(得分:2)
我对您的问题的理解是,对于每个userid
,您有两个条目,但想要随机提取一个。
要实现这一点,您应该为每个唯一userid
生成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);
这样,您可以获得似乎随机抽取的内容。真正发生的是用户ID是相关的,你只有几十种不同的提取可能。但是只使用简单的运算符,而且没有JOIN,这个查询非常快。