【问题标题】:More efficient way to perform multiple MySQL queries in PHP在 PHP 中执行多个 MySQL 查询的更有效方法
【发布时间】:2014-09-24 00:08:38
【问题描述】:

我有一家拥有数千个订单的在线商店,我正在编写一些查询以了解每个供应商(品牌)在该网站上赚了多少钱。我有以下查询,所选年份的每个月都有一个查询:

$filterJan = "$filterYear-01";
$queryJan = "SELECT price, quantity FROM order_items WHERE productID='$productID' AND timestamp LIKE '%$filterJan%' LIMIT 10000";
$suppliersQueryFilter = mysql_query($queryJan, $connection) or die(mysql_error());

while($rowF = mysql_fetch_assoc($suppliersQueryFilter)) {
    $price = $rowF["price"]*$rowF["quantity"];
    $totalJan = $totalJan+$price;
}

** 每月以此类推**

加载需要很长时间(我们所说的时间至少超过 60 秒),而且我知道它在任何形式或形式上都没有效率。每个月,这些查询都在搜索数千条记录。是否有更有效的方法或将其写入:

a) 将代码量减少到可能 1 个查询 b) 提高​​加载时间的效率

$filterYear 包含年份,例如 2009。

因此,此查询的作用是选择选定年份(分配给 $filterYear)每个月赚了多少钱。所以它生成的结果是一张包含一月、二月、三月的表格……每个月赚了多少钱,所以是 2345 英镑、2101 英镑等等……

【问题讨论】:

  • 是的。请改用一个查询。
  • 一个查询通常比 12 更有效,尤其是在结果上进行那些可怕的循环以获得每个月的总价格(使用 SQL 的 SUM() 聚合函数);但是您查看过 order_items 表上的索引吗?
  • @Strawberry 如何将其转换为 1 个查询? (我不是最好的)
  • 并为您的时间戳列使用其他过滤器。 LIKE '%anything%' 不能通过索引来帮助。您可以使用简单的 BETWEEN ... AND 或类似的。
  • 对年/月使用 GROUP BY 子句

标签: php mysql sql performance


【解决方案1】:

你应该将你的时间戳存储为一个实际的 mysql 日期时间值,这会使事情像

GROUP BY YEAR(timestamp), MONTH(timestamp)
WHERE timestamp BETWEEN $initialtime AND $finaltime

微不足道的可能。这会将您的多个基本相同的重复查询减少为一个查询。

您可以为此使用派生值,但效率会低于使用本机日期时间字段:

GROUP BY SUBSTR(timestamp, 0, 4), SUBSTR(timestamp, 6,2)

【讨论】:

  • +1 这是正确的方法。 OP 还希望包含YEAR(timestamp)MONTH(timestamp),并使用SUM(price*qty) 聚合。 (OP 代码似乎只是增加了价格,而忽略了数量,这似乎不对。)也不清楚为什么 OP 查询中有 LIMIT 10000; OP 真的只对每个月的前 10,000 行感兴趣吗?这似乎也不对。
【解决方案2】:

为了获得最佳性能,您需要向数据库提交类似这样的查询:

SELECT DATE_FORMAT(i.timestamp,'%Y-%m') AS `month`
     , SUM(i.price*i.qty)               AS `total`
  FROM order_items i 
 WHERE i.productID  = 'foo'
   AND i.timestamp >= '2013-01-01'
   AND i.timestamp <  '2013-01-01' + INTERVAL 12 MONTH
 GROUP
    BY DATE_FORMAT(i.timestamp,'%Y-%m')

(假设timestamp 列是MySQL 数据类型TIMESTAMPDATETIMEDATE

使用已弃用的 mysql_ 接口,您希望避免使用 mysql_real_escape_string 函数的 SQL 注入漏洞。 (更好的选择是使用 mysqli 或 PDO 接口,并使用带有绑定占位符的准备好的语句。)

我们希望时间戳上的谓词位于 BARE 列上,因此 MySQL 可以利用可用的合适索引进行范围扫描操作,而不是要求对表中的每一行进行全扫描。

我们还希望利用服务器的强大功能快速得出总计,并仅返回总计,而不是检索每个翻转的行,并单独处理每一行(RBAR = 逐行处理)

GROUP BY 子句和 SUM() 聚合函数是为适应这个结果量身定制的。

使用 mysql_ 接口,查询看起来像这样:

$querytext = "
SELECT DATE_FORMAT(i.timestamp,'%Y-%m') AS `month`
     , SUM(i.price*i.qty)               AS `total`
  FROM order_items i 
 WHERE i.productID  = '" . mysql_real_escape_string($thisProductID) . "'
   AND i.timestamp >= '" . mysql_real_escape_string($filterYear) . "-01-01'
   AND i.timestamp <  '" . mysql_real_escape_string($filterYear) . "-01-01' + 
                      INTERVAL 12 MONTH
 GROUP BY DATE_FORMAT(i.timestamp,'%Y-%m')";

# for debugging
#echo $querytext;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-10-30
    • 2018-05-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多