【发布时间】:2016-07-22 04:20:00
【问题描述】:
我正在使用 Prestashop 相关产品 PRO 插件,它在显示来自同一类别的一些随机产品时非常有用,但它使用默认 Prestashop ORDER BY RAND 方法并且当我启用此方法以显示该产品的 24 个随机产品时页面空闲加载时间从 4000 毫秒到 7000 毫秒,因为它正在等待数据库显示一些随机产品。
当我将它减少到 8 个产品时,它是 1500-2000 毫秒,但在 SEO 得分方面仍然太长。我一直在寻找插件中的解决方案,但我无法弄清楚,但我发现了这个:
这里是 Presta 1.6.1.4。在 classes\Category.php 中,关于第 744 行的内容是这样的:
$sql = 'SELECT p.*, product_shop.*, stock.out_of_stock, IFNULL(stock.quantity, 0) AS quantity'.(Combination::isFeatureActive() ? ', IFNULL(product_attribute_shop.id_product_attribute, 0) AS id_product_attribute,
product_attribute_shop.minimal_quantity AS product_attribute_minimal_quantity' : '').', pl.`description`, pl.`description_short`, pl.`available_now`,
pl.`available_later`, pl.`link_rewrite`, pl.`meta_description`, pl.`meta_keywords`, pl.`meta_title`, pl.`name`, image_shop.`id_image` id_image,
il.`legend` as legend, m.`name` AS manufacturer_name, cl.`name` AS category_default,
DATEDIFF(product_shop.`date_add`, DATE_SUB("'.date('Y-m-d').' 00:00:00",
INTERVAL '.(int)$nb_days_new_product.' DAY)) > 0 AS new, product_shop.price AS orderprice
FROM `'._DB_PREFIX_.'category_product` cp
LEFT JOIN `'._DB_PREFIX_.'product` p
ON p.`id_product` = cp.`id_product`
'.Shop::addSqlAssociation('product', 'p').
(Combination::isFeatureActive() ? ' LEFT JOIN `'._DB_PREFIX_.'product_attribute_shop` product_attribute_shop
ON (p.`id_product` = product_attribute_shop.`id_product` AND product_attribute_shop.`default_on` = 1 AND product_attribute_shop.id_shop='.(int)$context->shop->id.')':'').'
'.Product::sqlStock('p', 0).'
LEFT JOIN `'._DB_PREFIX_.'category_lang` cl
ON (product_shop.`id_category_default` = cl.`id_category`
AND cl.`id_lang` = '.(int)$id_lang.Shop::addSqlRestrictionOnLang('cl').')
LEFT JOIN `'._DB_PREFIX_.'product_lang` pl
ON (p.`id_product` = pl.`id_product`
AND pl.`id_lang` = '.(int)$id_lang.Shop::addSqlRestrictionOnLang('pl').')
LEFT JOIN `'._DB_PREFIX_.'image_shop` image_shop
ON (image_shop.`id_product` = p.`id_product` AND image_shop.cover=1 AND image_shop.id_shop='.(int)$context->shop->id.')
LEFT JOIN `'._DB_PREFIX_.'image_lang` il
ON (image_shop.`id_image` = il.`id_image`
AND il.`id_lang` = '.(int)$id_lang.')
LEFT JOIN `'._DB_PREFIX_.'manufacturer` m
ON m.`id_manufacturer` = p.`id_manufacturer`
WHERE product_shop.`id_shop` = '.(int)$context->shop->id.'
AND cp.`id_category` = '.(int)$this->id
.($active ? ' AND product_shop.`active` = 1' : '')
.($front ? ' AND product_shop.`visibility` IN ("both", "catalog")' : '')
.($id_supplier ? ' AND p.id_supplier = '.(int)$id_supplier : '');
if ($random === true) {
$sql .= ' ORDER BY RAND() LIMIT '.(int)$random_number_products;
} else {
$sql .= ' ORDER BY '.(!empty($order_by_prefix) ? $order_by_prefix.'.' : '').'`'.bqSQL($order_by).'` '.pSQL($order_way).'
LIMIT '.(((int)$p - 1) * (int)$n).','.(int)$n;
}
如果我没记错的话,这负责在类别页面上展示产品(包括一些插件)。 rand()的订单真的很糟糕。如您所见,有一行
if ($random === true) {
$sql .= ' ORDER BY RAND() LIMIT '.(int)$random_number_products;
}
在我看来,这是我们可以开始一些改变的关键。我找到了一篇关于优化 MySQL ORDER BY RAND 查询的文章,得到了一些非常令人满意的结果。你可以在这里阅读它们
https://www.warpconduit.net/2011/03/23/selecting-a-random-record-using-mysql-benchmark-results/
这里
http://jan.kneschke.de/projects/mysql/order-by-rand/(在这种情况下,结果简直太棒了)
但是有一个案例。我的编程技能仅限于在 Prestashop 中实现这些方法:(这对我来说太复杂了,所以有人可以帮助我用一种新方法编辑这些行。有更好的经验和知识的人可以帮助我吗?或者发明一些东西比我建议的更好吗?
【问题讨论】:
-
你是对的。
ORDER BY RAND()是一个臭名昭著的反模式。您提出的解决方案是可以接受的。尤其是 Jan Kneschke 的。为了实现它们,如果您停止所有LIMIT操作,您将需要某种方式来了解或估计将出现在结果集中的行数。高估是可以接受的,但高估越大,查询性能就越差。 -
关键是我尝试实现他的方法,失败了。我只是无法在 Prestashop 中完成它。
-
您对无限结果集长度的估计是多少?
-
@OllieJones 我不明白你的问题。你能否让我更清楚 - 编程新手。 PS我尝试了简单的方法,就像
$sql .= ' AND RAND()<(SELECT (('.(int)$random_number_products.'/COUNT(*))*10) FROM'._DB_PREFIX_.'category_product) ORDER BY RAND() LIMIT '.(int)$random_number_products;这样的简单方法,但它只显示很少的结果并且一直没有工作。 -
暂时忘记编程难题。您的产品总列表中有多少行? (你店里有多少产品?)你怎么知道?
标签: php mysql optimization random prestashop