2011-10-31 74 views
0

所以我有这个相对简单的查询拉基于一些标准排随机从两个不同的MyISAM表:如何优化缓慢的MySQL查询由于ORDER BY RAND()?

SELECT 
    table1 . * , table2 . * 
FROM 
    Table1 AS table1 
LEFT JOIN 
    Table2 AS table2 
USING (
    col1 
) 
WHERE 
    table1.col1 != '5324372' 
AND 
    table1.col2 LIKE 'S' 
AND (
    table1.col3 LIKE 'I' 
    OR table1.col3 LIKE 'V-G' 
) 
AND (
    table2.col1 = 'A' 
    OR table2.col2 = 'B' 
) 
ORDER BY RAND() 
LIMIT 1 

...这在开始工作得很好,但我的数据库开始增长,现在需要几秒钟才能执行。

上面使用的所有列都被索引,所以它不是一个索引问题。

从我研究过的情况来看,这是由于ORDER BY RAND()这条线在大桌子上显然运行非常缓慢。

我已经看到了这个问题的一些潜在的解决方案,但它们相当神秘,而且我无法将我的头围绕我的上述查询进行包裹。

我真的很惊讶MySQL没有内置解决方案来解决这个非常缓慢的ORDER BY RAND()问题,因为在我看来,这对于需要选择随机行的许多类型的应用程序来说是非常基本的需求。

那么如何优化上面的查询,以便在没有很长的执行时间的情况下获得相同/相似的效果?

回答

1

您只选择一行,我认为您可以随机选择一行随机LIMIT。例如:

如果您有:

SELECT * table ORDER BY RAND() LIMIT 1; 

将其更改为

SELECT * table LIMIT $randomvalue ,$randomvalue + 1; 

$随机值是从应用层面选择的随机值。

更新:下面的答案比上面的答案更清楚。

//get the total number of rows 
$result= mysql_query(" SELECT COUNT(*) AS total FROM `table` "); 
$row = mysql_fetch_array($result); 
$total=$row['total']; 


//create random value from 1 to the total of rows 
$randomvalue =rand(1,$total); 


//get the random row 

$result= mysql_query(" SELECT * FROM `table` limit $randomvalue,1"); 
+0

我更喜欢纯粹的MySQL解决方案来解决这个问题。然而,在你的解决方案中,我将如何计算$ randomvalue,我将如何计算它? – ProgrammerGirl

+0

那么,选择一个介于1和预期行数之间的数字似乎是合乎逻辑的。它会将您预期的复杂度降低到O(N)。可能更多,因为你会避免大量的磁盘流量。 – wildplasser

+0

@程序员。我认为这是不可能的,因为wildplasser说。对于随机值,请确保它不超过总行数。 –

2

排序通常是N * log(N)操作。通常,查询规划器/生成器/优化器尽可能避免排序,将它与索引或子查询自然产生的顺序结合起来。随机排序不能以任何方式“优化”出来。解决方案:不要这样做。

+1

这个答案根本没有帮助我,因为我仍然需要能够为我的应用程序随机选择一行。 – ProgrammerGirl