【发布时间】:2011-09-01 15:46:58
【问题描述】:
我被分配了从一些保存的数据中为网站创建一些图形统计数据的任务。
事实: - 有 3 个数据库正在使用中。 dbCurrent、dbStats、dbBackup。 dbCurrent 是网站的主数据库 dbStats 保存各种统计表和跟踪数据 dbBackup 保存过去五年的统计/跟踪表。
- 我将使用的数据来自两个数据库(dbStats、dbBackup)
- 表名是:stats2006、stats2007、stats2008 等,除了当前的stats 只是“stats”。每个表格都有其年份的数据。
- 每一年数据的表结构都是一样的: primaryID 字段为整数 productID 字段为整数 dateMonitor 字段是整数(unixtimestamp) pageName 字段为 varchar (20)
- productID、dateMonitor、pageName 字段也有索引
换句话说,什么产品在什么日期从什么页面被浏览。
所以,我的想法是从每个表中创建一个循环并获取我的数据。 我的每个查询看起来像:
Select COUNT(primaryID) as myCounter FROM $tablename WHERE $conditions
其中 $tablename 和 $conditions 是基于每个循环的变量。 所有条件都类似于:
- date1 和 date2 之间的 dateMonitor
- pageName='some val'
- productID IN ($comma_separated_values)
- 以上组合
到目前为止,所有这些都运行良好(对于单个产品)。
当我尝试创建报告以比较“y”年中的“x”产品时(由管理员/版主动态选择),脚本运行时间超过 15 分钟。
我正在寻找一种方法来提高脚本的性能。 我目前使用的逻辑/结构如下:
Loop through products to find the ids to use (typical format is: x,y,z (comma separated values)
Open Loop through years/months
Execute one sql query for each affected table/database to get the number of affected rows.
Close year loop
Send data to graph script (jquery jqPlot to be exact) to print on screen
任何帮助/想法表示赞赏。
编辑: 基于@Narf 的 UNION ALL 建议,我基于 12 个子选择语句构建了 1 个单一查询:
SELECT COUNT(*) AS monthlyTotal FROM db1.table1 WHERE dateMonitor>='1167606001' AND dateMonitor<='1170284399' AND dateMonitor='test'
UNION ALL
SELECT COUNT(*) AS monthlyTotal FROM db1.table2 WHERE dateMonitor>='1170284401' AND dateMonitor<='1172703599' AND dateMonitor='test' ...
每个 select 语句都引用一个月的持续时间。演示代码:
for ($m=1; $m<=12; $m++)
{
$startDate = mktime(0, 0, 1, $m, 1, $myYear);
$daysOfMonth = date("t", mktime(10, 10, 10, $m, 10, $myYear));
$endDate = mktime(23, 59, 59, $m, $daysOfMonth, $myYear);
$query_chk1 .= "SELECT COUNT(*) AS monthlyTotal FROM db1.table1 WHERE dateMonitor>='$startDate' AND dateMonitor<='$endDate' AND pageName='test' UNION ALL ";
}
$query_chk1 = substr($query_chk1, 0, -10);
EDIT2:创建组合索引后(如@ypercube 所建议),我发现执行时间略有减少。
现在我的平均执行时间是 11 分钟(原来的时间是 15-17 分钟)
这对减少执行时间有很大帮助。
谢谢。
【问题讨论】:
-
你的表有什么索引?
-
附注:与
COUNT(field)相比,COUNT(*)在 MySQL 中更快。并给出相同的结果,只要field不可为空。 -
@ypercube: productID, dateMonitor, pageName 字段是每个表中的索引
-
对于涉及多个条件(在多个字段中)的查询,您将从复合索引中受益。例如,
WHERE dateMonitor between date1 and date2 AND pageName='some val'将受益于(pageName, datemonitor)索引。
标签: php mysql optimization