如何解决与mysql随机错误
我有项目在php + mysql(超过2 000 000行)。请查看这个php代码。如何解决与mysql随机错误
<?php
for($i=0;$i<20;$i++)
{
$start = rand(1,19980);
$select_images_url_q = "SELECT * FROM photo_gen WHERE folder='$folder' LIMIT $start,2 ";
$result_select = (mysql_query($select_images_url_q));
while($row = mysql_fetch_array($result_select))
{
echo '<li class="col-lg-2 col-md-3 col-sm-3 col-xs-4" style="height:150px">
<img class="img-responsive" src="http://static.gif.plus/'.$folder.'/'.$row['code'].'_s.gif">
</li>';
}
}
?>
此代码工作$start = rand(1,19980);
位置很慢,请大家帮我怎样才能使与MySQL随机函数选择请求,谢谢
最好是先撰写你的SQL查询(如PHP字符串)一次,然后只执行一次。
或者你可以用这种方式是否适合你的情况来选择值:Select n random rows from SQL Server table
实际上,即使表有2+百万行,我猜测,一个给定的文件夹中有少得多。因此,这应该是与指数合理的photo_gen(folder)
:
SELECT *
FROM photo_gen
WHERE folder = '$folder'
ORDER BY rand()
LIMIT 40;
如果文件夹仍然可以有几万或几十万的例子,我会建议一个微小的变化:
SELECT pg.**
FROM photo_gen pg cross join
(select count(*) cnt from photo_gen where folder = $folder) as cnt
WHERE folder = '$folder' and
rand() < 500/cnt
ORDER BY rand()
LIMIT 40;
的WHERE
表达应该得到大约500行(取决于样本变异的变异)。有一个非常高的信心,至少有40(你不必担心它)。最后的排序应该很快。
确实有其他方法,但它们由where
子句复杂化。索引可能是您提高性能所需的关键。
http://www.webtrenches.com/post.cfm/avoid-rand-in-mysql - 与2+万条记录,'ORDER BY RAND()'似乎是一个坏主意。 –
对我来说是有趣的你的答案有-1 VODE向下 – Shafizadeh
@ScottArciszewski。 。 。关键是查询不会对所有数据进行排序。它需要几百行并对其进行排序。对于这类问题,排序几百行通常很好。您显然误解了查询逻辑。 –
根据您的代码使用$folder
所做的操作,您可能容易受到SQL injection的影响。
为了更好的安全性,请考虑转移到PDO或MySQLi和using prepared statements。我写了一个名为EasyDB的库,以便开发人员更容易采用更好的安全措施。
快速,神志清醒,和有效的方式从数据库中选择N个不同的随机元素如下:
- 获取符合你条件的行(即
WHERE folder = ?
)的数量。 - 生成一个介于0和这个数字之间的随机数。
- 像你一样选择一个给定偏移量的行。
- 将先前生成的行的ID存储在不断增长的列表中,以从结果中排除,并减少行数。
使用EasyDB一个例子如下:
// Connect to the database here:
$db = \ParagonIE\EasyDB\Factory::create(
'mysql;host=localhost;dbname=something',
'username',
'putastrongpasswordhere'
);
// Maintain an array of previous record IDs in $exclude
$exclude = array();
$count = $db->single('SELECT count(id) FROM photo_gen WHERE folder = ?', $folder);
// Select _up to_ 40 values. If we have less than 40 in the folder, stop
// when we've run out of photos to load:
$max = $count < 40 ? $count : 40;
// The loop:
for ($i = 0; $i < $max; ++$i) {
// The maximum value will decrease each iteration, which makes
// sense given that we are excluding one more result each time
$r = mt_rand(0, ($count - $i - 1));
// Dynamic query
$qs = "SELECT * FROM photo_gen WHERE folder = ?";
// We add AND id NOT IN (2,6,7,19, ...) to prevent duplicates:
if ($i > 0) {
$qs .= " AND id NOT IN (" . implode(', ', $exclude) . ")";
}
$qs .= "ORDER BY id ASC LIMIT ".$r.", 1";
$row = $db->row($qs, $folder);
/**
* Now you can operate on $row here. Feel free to copy the
* contents of your while($row=...) loop in place of this comment.
*/
// Prevent duplicates
$exclude []= (int) $row['id'];
}
Gordon's answer建议使用ORDER BY RAND()
,这in general is a bad idea并且可以使你的查询速度很慢。此外,尽管他说你不需要担心行数小于40行(可能是因为涉及到这个概率),但这种情况在将会失败。
的快速笔记mt_rand()
:这是一种偏见和可预测的随机数发生器只有4十亿可能的种子。如果你想要更好的效果,look into random_int()
(仅PHP 7,但我工作了PHP 5项目的兼容层上。更多信息请参阅链接的答案。)
。 。你对我的回答的陈述是不正确的。运行多个查询通常是一个坏主意。在这种情况下,对于20行,取决于与数据库结构和数据库连接有关的各种因素,它可能会或可能不会有效。 –
。 。您正在使用'limit'而没有'order by',所以任意行都被返回。我真的不明白代码应该做什么。 –
需要从数据库中随机获得40个元素 – Vahagn
刚刚更新了我的答案。 –