我正在优化我的项目中的许多现有查询。 Quassnoi 的解决方案帮助我加快了查询速度!但是,我发现很难将上述解决方案整合到所有查询中,尤其是对于涉及多个大表上的许多子查询的复杂查询。
所以我使用的是优化程度较低的解决方案。从根本上说,它的工作方式与 Quassnoi 的解决方案相同。
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;'
AND rand() <= $size * $factor / [accomodation_table_row_count]
LIMIT $size
$size * $factor / [accomodation_table_row_count] 计算出随机选择行的概率。 rand() 将生成一个随机数。如果 rand() 小于或等于概率,则将选择该行。这有效地执行随机选择以限制表大小。由于它有可能返回小于定义的限制计数,因此我们需要增加概率以确保我们选择了足够的行。因此,我们将 $size 乘以 $factor(我通常设置 $factor = 2,在大多数情况下都有效)。最后我们做limit $size
现在的问题是计算 accomodation_table_row_count。
如果我们知道表格大小,我们可以硬编码表格大小。这将运行得最快,但显然这并不理想。如果您使用 Myisam,获取表数非常有效。由于我使用的是innodb,所以我只是在做一个简单的计数+选择。在你的情况下,它看起来像这样:
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;'
AND rand() <= $size * $factor / (select (SELECT count(*) FROM `accomodation`) * (SELECT count(*) FROM `accomodation_category`))
LIMIT $size
棘手的部分是计算出正确的概率。如您所见,以下代码实际上只计算了粗略的临时表大小(实际上,太粗略了!):(select (SELECT count(*) FROM accomodation) * (SELECT count(*) FROM accomodation_category)) 但您可以改进此逻辑以提供更接近的表大小近似值。 请注意,过度选择比选择不足的行更好。即,如果概率设置得太低,您可能无法选择足够的行。
这个解决方案比 Quassnoi 的解决方案运行得慢,因为我们需要重新计算表格大小。但是,我发现这种编码更易于管理。这是准确性+性能与编码复杂性之间的权衡。话虽如此,在大型表上,这仍然比 Order by Rand() 快得多。
注意:如果查询逻辑允许,请在任何连接操作之前尽早执行随机选择。