简体   繁体   English

在PHP中执行多个MySQL查询的更有效方法

[英]More efficient way to perform multiple MySQL queries in PHP

I have an online store with thousands of orders and I'm writing some queries to figure out how much money each supplier (brand) has made on the site. 我有一个在线商店,有数千个订单,并且我正在写一些查询查询每个供应商(品牌)在网站上赚了多少钱。 I have the following queries, one for every month of the selected year: 我有以下查询,所选年份的每个月查询一次:

$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;
}

** and so on for each month ** **每月依此类推**

It takes ages to load (we're talking over 60 seconds at least) and I know it is not efficient in any shape or form. 加载需要花费很多时间(至少要说60秒以上),而且我知道它在任何形状或形式上都不有效。 For each month these queries are searching through thousands of records. 这些查询每个月都会搜索成千上万条记录。 Is there a more efficient way or writing this to: 有没有更有效的方法或将其编写为:

a) Reduce the amount of code to maybe 1 query b) Make it more efficient to increase loading times a)将代码量减少到大约1个查询b)使其更有效地增加加载时间

$filterYear contains a year, like 2009. $ filterYear包含一年,例如2009。

So what this query does is it selects how much money has been made for each month for a selected year (which is assigned to $filterYear). 因此,此查询的作用是选择选定年份(分配给$ filterYear)每个月赚多少钱。 So the result it generates is a table with Jan, Feb, March... with how much money has been made each month, so £2345, £2101, etc... 因此,它生成的结果是一张表,其中包含1月,2月,3月...每个月赚了多少钱,所以2345英镑,2101英镑等。

You should be storing your timestamp as an actual mysql datetime value, which would make things like 您应该将时间戳存储为实际的mysql datetime值,这将使

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

trivially possible. 可能的。 That'd reduce your multiple essentially identical repeated queries to just one single query. 这样可以将多个基本相同的重复查询减少为一个查询。

You can use derived values for this, but it'll be less efficient than using a native datetime field: 您可以为此使用派生值,但效率不如使用本机datetime字段:

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

For best performance, you'd want to submit a query something like this to the database: 为了获得最佳性能,您想要向数据库提交类似这样的查询:

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')

(This assumes that the timestamp column is MySQL datatype TIMESTAMP , DATETIME or DATE ) (这假设timestamp列是MySQL数据类型TIMESTAMPDATETIMEDATE

Using the deprecated mysql_ interface, you want to avoid SQL Injection vulnerabilities using the mysql_real_escape_string function. 使用不推荐使用的mysql_接口,您想使用mysql_real_escape_string函数避免SQL注入漏洞。 (A better option would be to use the mysqli or PDO interface, and use a prepared statement with bind placeholders.) (更好的选择是使用mysqli或PDO接口,并使用带有绑定占位符的预处理语句。)

We want the predicates on the timestamp to be on the BARE column, so MySQL can make use of an available suitable index for a range scan operation, rather than requiring a full scan of every row in the table. 我们希望时间戳上的谓词在BARE列中,因此MySQL可以为范围扫描操作使用可用的合适索引,而不需要对表中的每一行进行全面扫描。

We also want to use the power of the server to quickly derive a total, and return just the total, rather than retrieving every flipping row, and processing each of those rows individually (RBAR = row by agonizing row) 我们还希望利用服务器的功能来快速得出总计,并仅返回总计,而不是检索每个翻转行,并分别处理这些行中的每一个(RBAR =通过折行来排行)

The GROUP BY clause and the SUM() aggregate function are tailor made to suit this result. GROUP BY子句和SUM()聚合函数是为适应此结果而量身定制的。

With mysql_ interface, the query would look something like this: 使用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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM