我正在尝试从数据库中提取一张带有图片的随机文章。
SELECT FLOOR(MAX(id) * RAND()) FROM `table` WHERE `picture` IS NOT NULL
我的桌子是33 MB大,有1,006,394篇文章,但只有816张图片。 我的问题是这个查询需要0.4640 sek
我需要这个更快更快。 任何想法都是受欢迎的。
P.S。 1.当然我有id的索引。 2.图片字段没有索引。我应该加一个吗? 3.产品名称是唯一的,也是产品编号,但这是不可能的。
@cHao 当我使用它来选择带图片的随机条目之一时,解决方案会更快。(小于0.1秒。 但如果我尝试相反的话,它会慢一点,选择一个没有图片的随机文章。 2..3秒
@Kickstart 的解决方案在尝试查找带图片的条目时速度稍慢,但在尝试查找没有图片的条目时速度几乎相同。平均0,149秒。
@ bob-kruithof 的解决方案对我不起作用。 当试图找到带图片的条目时,它会选择一个没有图片的条目。
和@ ganesh-bora,是的,你是对的,在我的情况下,速度差异约为5..15倍。
我要感谢大家的帮助,我决定参加@Kickstart。
答案 0 :(得分:1)
您可以尝试将随机数附加到每一行,然后按此排序。数字最小的行将位于顶部。
SELECT `table`.`id`, RAND() as `order`
FROM `table`
WHERE `picture` IS NOT NULL
ORDER BY `order`
LIMIT 1;
这当然比用RAND()
标记ID更慢,但是(1)它总是会给你一个有效的ID(只要有一个非空图片字段的记录)无论如何),以及(2)WTF比率相当低;大多数人都可以知道这里发生了什么。 :)当选择的项目数量相对较少(约1%)时,它的性能可以与Kickstart's solution相匹配,并且具有适当的索引表。绝对不要试图从像这样的整个巨大的桌子中选择;首先在某些索引字段上使用WHERE
子句限制它。
Performancewise,如果你有一个长期运行的应用程序(即:不是PHP;我说的是Java,.net等,即使在请求之间应用程序仍处于活动状态),您可能会尝试保留所有应用程序的列表带有图片的项目的ID,从该列表中选择随机ID,然后加载文章。如果你愿意的话,你也可以在PHP中做到这一点。当您每次都必须查询所有ID时,它可能无法正常工作,但如果您可以在APC中缓存ID列表,那么它可能非常有用。
答案 1 :(得分:1)
您需要获取具有匹配记录的一系列值,然后在该范围内找到匹配的记录。
这样的事情: -
SELECT r1.id
FROM `table` AS r1
INNER JOIN (
SELECT RAND( ) * ( MAX( id ) - MIN( id ) ) + MIN( id ) AS id
FROM `table`
WHERE `picture` IS NOT NULL
) AS r2
ON r1.id >= r2.id
WHERE `picture` IS NOT NULL
ORDER BY r1.id ASC
LIMIT 1
然而,对于任何效率的希望,你需要一个它正在检查的字段的索引(即你的例子中的picture
)
只是解释它是如何工作的。
子选择从表中查找随机id,该id位于图片记录的最小和最大ID之间。这个随机ID可能是也可能不是图片。
此子选择的结果ID将与主表联接,但使用> =并使用WHERE子句指定记录是图片记录。因此,它连接所有id大于或等于随机id的图片记录。最高随机ID将是具有最高id的图片记录的随机ID,因此它将始终找到记录(如果有任何图片记录)。然后使用ORDER BY / LIMIT返回单个id。
请注意,这有一个明显的缺陷,但大多数时候它都是无关紧要的。检索到的记录可能不完全是随机的。具有最低id的图片不太可能被返回(仅在RAND()返回0时才返回),但如果这很重要,则通过舍入生成的随机id很容易修复。另一个缺陷是,如果ids在整个范围内没有模糊地均匀分布,那么有些将比其他more更频繁地返回。例如,假设前1000个ID是图片的情况,那么直到最后一个(第33百万分之一)记录。随机id可以是3300万中的任何一个,但除非它小于或等于1000,否则它将是将返回的第33百万条记录。
答案 2 :(得分:0)
对于性能,您可以先在图片列上添加索引,这样814条记录在执行查询时会在顶部排序,然后您可以触发查询。
答案 3 :(得分:0)
我建议查看this article关于在mysql中选择随机行的不同方法。
SELECT name
FROM random JOIN
( SELECT CEIL( RAND() * (
SELECT MAX( id ) FROM random WHERE picture IS NOT NULL
) ) AS id ) AS r2 USING ( id );
这可能适用于您的情况。
picture
列上有索引吗?这可能会帮助您更快地获得结果。