我想优化我的查询,以便查看mysql-slow.log。
我的大多数慢速查询都包含ORDER BY RAND()。我无法找到真正的解决办法来解决这个问题。在MySQLPerformanceBlog有一个可能的解决方案,但我认为这还不够。对于优化不佳(或经常更新,用户管理)的表,它不能工作,或者我需要运行两个或多个查询才能选择我的PHP-generated随机行。
这个问题有什么解决办法吗?
一个虚拟的例子:
SELECT accomodation.ac_id,
accomodation.ac_status,
accomodation.ac_name,
accomodation.ac_status,
accomodation.ac_images
FROM accomodation, accomodation_category
WHERE accomodation.ac_status != 'draft'
AND accomodation.ac_category = accomodation_category.acat_id
AND accomodation_category.acat_slug != 'vendeglatohely'
AND ac_images != 'b:0;'
ORDER BY
RAND()
LIMIT 1发布于 2009-08-07 13:01:53
试试这个:
SELECT *
FROM (
SELECT @cnt := COUNT(*) + 1,
@lim := 10
FROM t_random
) vars
STRAIGHT_JOIN
(
SELECT r.*,
@lim := @lim - 1
FROM t_random r
WHERE (@cnt := @cnt - 1)
AND RAND(20090301) < @lim / @cnt
) i这在MyISAM上尤其有效(因为COUNT(*)是即时的),但即使在InnoDB中,10的效率也比ORDER BY RAND()高出一倍。
这里的主要思想是,我们不进行排序,而是保留两个变量,并计算要在当前步骤中选择的行的running probability。
有关更多细节,请参阅我博客中的这篇文章:
更新:
如果您只需要选择一个随机记录,请尝试如下:
SELECT aco.*
FROM (
SELECT minid + FLOOR((maxid - minid) * RAND()) AS randid
FROM (
SELECT MAX(ac_id) AS maxid, MIN(ac_id) AS minid
FROM accomodation
) q
) q2
JOIN accomodation aco
ON aco.ac_id =
COALESCE
(
(
SELECT accomodation.ac_id
FROM accomodation
WHERE ac_id > randid
AND ac_status != 'draft'
AND ac_images != 'b:0;'
AND NOT EXISTS
(
SELECT NULL
FROM accomodation_category
WHERE acat_id = ac_category
AND acat_slug = 'vendeglatohely'
)
ORDER BY
ac_id
LIMIT 1
),
(
SELECT accomodation.ac_id
FROM accomodation
WHERE ac_status != 'draft'
AND ac_images != 'b:0;'
AND NOT EXISTS
(
SELECT NULL
FROM accomodation_category
WHERE acat_id = ac_category
AND acat_slug = 'vendeglatohely'
)
ORDER BY
ac_id
LIMIT 1
)
)这假设您的ac_id的分布或多或少是均匀的。
发布于 2009-08-08 23:31:04
这取决于你需要的随机性。你联系的解决方案很管用,海事组织。除非您在ID字段中有很大的空白,否则仍然是随机的。
但是,您应该能够在一个查询中使用以下方法(用于选择单个值):
SELECT [fields] FROM [table] WHERE id >= FLOOR(RAND()*MAX(id)) LIMIT 1其他解决办法:
random的永久浮点数字段,并将其填充为随机数。然后,您可以在PHP中生成一个随机数并执行"SELECT ... WHERE rnd > $random"。发布于 2009-08-07 21:00:59
我是这样做的:
SET @r := (SELECT ROUND(RAND() * (SELECT COUNT(*)
FROM accomodation a
JOIN accomodation_category c
ON (a.ac_category = c.acat_id)
WHERE a.ac_status != 'draft'
AND c.acat_slug != 'vendeglatohely'
AND a.ac_images != 'b:0;';
SET @sql := CONCAT('
SELECT a.ac_id,
a.ac_status,
a.ac_name,
a.ac_status,
a.ac_images
FROM accomodation a
JOIN accomodation_category c
ON (a.ac_category = c.acat_id)
WHERE a.ac_status != ''draft''
AND c.acat_slug != ''vendeglatohely''
AND a.ac_images != ''b:0;''
LIMIT ', @r, ', 1');
PREPARE stmt1 FROM @sql;
EXECUTE stmt1;https://stackoverflow.com/questions/1244555
复制相似问题