Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/242.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 请提供复杂SQL查询优化建议_Php_Mysql_Sql_Database - Fatal编程技术网

Php 请提供复杂SQL查询优化建议

Php 请提供复杂SQL查询优化建议,php,mysql,sql,database,Php,Mysql,Sql,Database,在此处输入code我有一个结构如下的表: | ID (bigint) | APPID (Bigint)| USAGE_START_TIME (datetime) | SESSION_TIME (bigint) | USERID (bigint) | ----------------------------------------------------------------------------------------------------------- | 1

在此处输入code
我有一个结构如下的表:

| ID (bigint) | APPID (Bigint)| USAGE_START_TIME (datetime) | SESSION_TIME (bigint) |  USERID (bigint)   |
-----------------------------------------------------------------------------------------------------------
|  1          |        1      |         2013-05-03 04:42:55 |       400             |       12           |
|  2          |        1      |         2013-05-12 06:22:45 |       200             |       12           |
|  3          |        2      |         2013-06-12 08:44:24 |       350             |       12           |
|  4          |        2      |         2013-06-24 04:20:56 |         2             |       12           |
|  5          |        3      |         2013-06-26 08:20:26 |         4             |       12           |
|  6          |        4      |         2013-09-12 05:48:27 |        50             |       12           |
现在,如果put是userid,我想得到过去6个月每个月(所有应用程序)的总会话时间(总和)

如果一个应用在一个月内使用超过一次(基于使用情况\开始\时间),则该应用的总和中只应包括最近的会话\时间

对于上面的示例,结果应该是这样的(如果当前月份是10月,输入是userid=13):

此处,月份以数字形式表示月份(例如:10表示10月)

目前,我每个月都使用单独的查询。例如:

SELECT 
COALESCE(SUM(failcount),0) AS TOTAL_SESSION_TIME , MONTH(CURRENT_DATE) AS MONTH 
FROM appstime 
WHERE MONTH(`USAGE_START_TIME`) = MONTH(CURRENT_DATE) AND userid=12
但这并没有给我预期的结果

另外,我想知道我是否可以通过单个查询而不是每个月的查询来实现这一点。 我正在使用PHP+Mysql

请检查此处的sql FIDLE

谢谢你,

Sash

您是否需要
分组依据

SELECT 
SUM(COALESCE(SESSION_TIME,0)) AS TOTAL_SESSION_TIME , 
MONTH(USAGE_START_TIME) AS THE_MONTH 
FROM appstime 
WHERE userid=13 AND 
DATE(SESSION_TIME) > DATE_SUB(NOW(), INTERVAL 6 MONTH)
GROUP BY THE_MONTH
更新: 这会将结果限制为每个appid每月的最大日期:

SELECT 
SUM(COALESCE(session_time,0)) AS TOTAL_SESSION_TIME , 
MONTH(usage_start_time) AS THE_MONTH 
FROM appstime 
INNER JOIN
    (
    SELECT appid , MAX(usage_start_time) AS max_app_date
    FROM appstime
    GROUP BY appid
    ) grouped_apps ON 
      grouped_apps.appid = appstime.appid AND
      grouped_apps.max_app_date = appstime.usage_start_time
WHERE userid=12 
GROUP BY THE_MONTH

您想要分组方式吗

SELECT 
SUM(COALESCE(SESSION_TIME,0)) AS TOTAL_SESSION_TIME , 
MONTH(USAGE_START_TIME) AS THE_MONTH 
FROM appstime 
WHERE userid=13 AND 
DATE(SESSION_TIME) > DATE_SUB(NOW(), INTERVAL 6 MONTH)
GROUP BY THE_MONTH
更新: 这会将结果限制为每个appid每月的最大日期:

SELECT 
SUM(COALESCE(session_time,0)) AS TOTAL_SESSION_TIME , 
MONTH(usage_start_time) AS THE_MONTH 
FROM appstime 
INNER JOIN
    (
    SELECT appid , MAX(usage_start_time) AS max_app_date
    FROM appstime
    GROUP BY appid
    ) grouped_apps ON 
      grouped_apps.appid = appstime.appid AND
      grouped_apps.max_app_date = appstime.usage_start_time
WHERE userid=12 
GROUP BY THE_MONTH

您需要使用聚合函数(即,
分组依据
):


编辑仅通过
userid
appid
显示任何月份的最新
会话时间
。请注意,因此,调用此字段
total\u session\u time
可能不是一个好主意

select    latest.userid,
          latest.appid,
          month(latest.usage_start_time) as month,
          latest.session_time as latest_session_time

from      appstime as latest

left join appstime as later
on        later.userid           = latest.userid
and       later.appid            = latest.appid
and       later.usage_start_time > latest.usage_start_time

where     later.id is null;

您需要使用聚合函数(即,
分组依据
):


编辑仅通过
userid
appid
显示任何月份的最新
会话时间
。请注意,因此,调用此字段
total\u session\u time
可能不是一个好主意

select    latest.userid,
          latest.appid,
          month(latest.usage_start_time) as month,
          latest.session_time as latest_session_time

from      appstime as latest

left join appstime as later
on        later.userid           = latest.userid
and       later.appid            = latest.appid
and       later.usage_start_time > latest.usage_start_time

where     later.id is null;

如果我正确理解了您的问题,那么这应该是您的查询(当前日期的IBM DB2语法):

这将统计过去6个月每月的所有会话时间

干杯

编辑:
这将获取当月来自同一应用程序的所有应用程序调用。要从同一应用程序id获取最后一次呼叫,您需要一个存储过程来执行此操作。每个月有6个变量,如果日期大于同一个月的最后一个日期,则在select循环中进行检查。我建议您使用MySQL的等效日期(current date)函数来比较从0年开始的日期(以天为单位)。

如果我正确理解您的问题,那么这应该是您的查询(当前日期的IBM DB2语法):

这将统计过去6个月每月的所有会话时间

干杯

编辑:
这将获取当月来自同一应用程序的所有应用程序调用。要从同一应用程序id获取最后一次呼叫,您需要一个存储过程来执行此操作。每个月有6个变量,如果日期大于同一个月的最后一个日期,则在select循环中进行检查。我建议您使用MySQL的等效天数(当前日期)功能,以天为单位比较自0年以来的日期。

未测试,但类似于以下内容:-

SELECT ForMonths.aMonth, IFNULL(SUM(SESSION_TIME), 0)
FROM
(
    SELECT MONTH(DATE_ADD(NOW(), INTERVAL aInt MONTH)) AS aMonth
    FROM
    (
        SELECT 0 AS aInt UNION SELECT -1 UNION SELECT -2 UNION SELECT -3 UNION SELECT -4 UNION SELECT -5
    ) aCnt
) ForMonths
LEFT OUTER JOIN 
(
    SELECT a.USERID, a.APPID, aMonth, SESSION_TIME
    FROM appstime a
    INNER JOIN
    (
        SELECT USERID, APPID, MONTH(USAGE_START_TIME) AS aMonth, MAX(USAGE_START_TIME) AS USAGE_START_TIME
        FROM appstime
        GROUP BY USERID, APPID, aMonth
    ) b
    ON a.USERID = b.USERID
    AND a.USAGE_START_TIME = b.USAGE_START_TIME
    AND a.APPID = b.APPID
  WHERE a.USERID = 12
) ForDetails
ON ForMonths.aMonth = ForDetails.aMonth
GROUP BY ForMonths.aMonth
可以简化,但只需一个子查询即可获得过去6个月的每个月,并将该子查询与另一个子查询合并,即可获得用户每个月的最新金额

编辑-使用年和月:-

SELECT ForMonths.aMonth, IFNULL(SUM(SESSION_TIME), 0)
FROM
(
    SELECT EXTRACT(YEAR_MONTH FROM DATE_ADD(NOW(), INTERVAL aInt MONTH)) AS aMonth
    FROM
    (
        SELECT 0 AS aInt UNION SELECT -1 UNION SELECT -2 UNION SELECT -3 UNION SELECT -4 UNION SELECT -5
    ) aCnt
) ForMonths
LEFT OUTER JOIN 
(
    SELECT a.USERID, a.APPID, aMonth, SESSION_TIME
    FROM appstime a
    INNER JOIN
    (
        SELECT USERID, APPID, EXTRACT(YEAR_MONTH FROM USAGE_START_TIME) AS aMonth, MAX(USAGE_START_TIME) AS USAGE_START_TIME
        FROM appstime
        GROUP BY USERID, APPID, aMonth
    ) b
    ON a.USERID = b.USERID
    AND a.USAGE_START_TIME = b.USAGE_START_TIME
    AND a.APPID = b.APPID
  WHERE a.USERID = 12
) ForDetails
ON ForMonths.aMonth = ForDetails.aMonth
GROUP BY ForMonths.aMonth
ORDER BY ForMonths.aMonth

未测试,但类似于以下内容:-

SELECT ForMonths.aMonth, IFNULL(SUM(SESSION_TIME), 0)
FROM
(
    SELECT MONTH(DATE_ADD(NOW(), INTERVAL aInt MONTH)) AS aMonth
    FROM
    (
        SELECT 0 AS aInt UNION SELECT -1 UNION SELECT -2 UNION SELECT -3 UNION SELECT -4 UNION SELECT -5
    ) aCnt
) ForMonths
LEFT OUTER JOIN 
(
    SELECT a.USERID, a.APPID, aMonth, SESSION_TIME
    FROM appstime a
    INNER JOIN
    (
        SELECT USERID, APPID, MONTH(USAGE_START_TIME) AS aMonth, MAX(USAGE_START_TIME) AS USAGE_START_TIME
        FROM appstime
        GROUP BY USERID, APPID, aMonth
    ) b
    ON a.USERID = b.USERID
    AND a.USAGE_START_TIME = b.USAGE_START_TIME
    AND a.APPID = b.APPID
  WHERE a.USERID = 12
) ForDetails
ON ForMonths.aMonth = ForDetails.aMonth
GROUP BY ForMonths.aMonth
可以简化,但只需一个子查询即可获得过去6个月的每个月,并将该子查询与另一个子查询合并,即可获得用户每个月的最新金额

编辑-使用年和月:-

SELECT ForMonths.aMonth, IFNULL(SUM(SESSION_TIME), 0)
FROM
(
    SELECT EXTRACT(YEAR_MONTH FROM DATE_ADD(NOW(), INTERVAL aInt MONTH)) AS aMonth
    FROM
    (
        SELECT 0 AS aInt UNION SELECT -1 UNION SELECT -2 UNION SELECT -3 UNION SELECT -4 UNION SELECT -5
    ) aCnt
) ForMonths
LEFT OUTER JOIN 
(
    SELECT a.USERID, a.APPID, aMonth, SESSION_TIME
    FROM appstime a
    INNER JOIN
    (
        SELECT USERID, APPID, EXTRACT(YEAR_MONTH FROM USAGE_START_TIME) AS aMonth, MAX(USAGE_START_TIME) AS USAGE_START_TIME
        FROM appstime
        GROUP BY USERID, APPID, aMonth
    ) b
    ON a.USERID = b.USERID
    AND a.USAGE_START_TIME = b.USAGE_START_TIME
    AND a.APPID = b.APPID
  WHERE a.USERID = 12
) ForDetails
ON ForMonths.aMonth = ForDetails.aMonth
GROUP BY ForMonths.aMonth
ORDER BY ForMonths.aMonth

虽然我在获取6个月的记录时遇到了问题,但我本可以在我的另一台机器上完成,但在当前机器上没有MySQL。我从Kickstart(因为他在那里的信誉)那里删掉了那部分

无论如何,我从6个月前和现在的12个用户开始,开始了一个最内在的“预查询”(别名PQ)。为了确保我不只是从今天(本月2日)算起6个月,或者即使是在本月26日算起,而是想要6个月前的第一天,我做了一些日期计算,先到6个月前的最后一天,然后在下个月的第一天加上1天。因此,这将创造

10月2-6个月=4月2日。。。然后移到4月30日的最后一天,然后再加上1天到5月1日。现在,从5月1日到10月1日,其中10月是第6个月,如果1天到整个月。如果你想从4月1日到现在,那就回到7个月前

因此,我将每月获得每个应用程序、用户和每个月的最大实例。我将用户包括在内,以防将来需要所有用户,而不仅仅是一个

一旦查询到每个应用程序/用户/月的MAX(),我就会再次加入会话,但只加入匹配的会话

最后,通过一个左连接应用到外部月份列表中,剩下的就剩下了。同样,如果需要所有用户,可以将用户添加到外部查询和GROUPBY子句中

SELECT
      AllMonths.aMonth,
      COALESCE( SUM( Ap2.Session_Time ), 0 ) as Total_Session_Time
   from
      ( SELECT MONTH(DATE_ADD(NOW(), INTERVAL aInt MONTH)) AS aMonth
           FROM
            (
                SELECT 0 AS aInt 
                    UNION SELECT -1 
                    UNION SELECT -2 
                    UNION SELECT -3 
                    UNION SELECT -4 
                    UNION SELECT -5
            ) aCnt ) AllMonths
      LEFT JOIN
         ( select
                 appstime.AppID,
                 appstime.UserID,
                 MONTH( appstime.Usage_Start_Time ) as PerMonth,
                 MAX( appstime.Usage_Start_Time ) as ThisTime
              from 
                 ( select @StartDate := last_day( now() - interval 6 month ) + interval 1 day ) sqlvars,
                 appstime
              where
                     appstime.Usage_Start_Time >= @StartDate
                 AND appstime.UserID = 12
              group by
                 appstime.AppID,
                 appstime.UserID,
                 MONTH( appstime.Usage_Start_Time ) ) PQ
         ON AllMonths.aMonth = PQ.PerMonth
         LEFT JOIN appstime Ap2
             ON PQ.AppID = Ap2.AppID
            AND PQ.UserID = Ap2.UserID
            AND PQ.ThisTime = Ap2.Usage_Start_Time
   group by         
      AllMonths.aMonth

虽然我在获取6个月的记录时遇到了问题,但我本可以在我的另一台机器上完成,但在当前机器上没有MySQL。我从Kickstart(因为他在那里的信誉)那里删掉了那部分

无论如何,我从6个月前和现在的12个用户开始,开始了一个最内在的“预查询”(别名PQ)。为了确保我不只是从今天(本月2日)算起6个月,或者即使是在本月26日算起,而是想要6个月前的第一天,我做了一些日期计算,先到6个月前的最后一天,然后在下个月的第一天加上1天。因此,这将创造

10月2-6个月=4月2日。。。然后移到4月30日的最后一天,然后再加上1天到5月1日。现在,从5月1日到10月1日,其中10月是第6个月,如果1天到整个月。如果你想从4月1日到现在,那就回到7个月前

因此,我将每月获得每个应用程序、用户和每个月的最大实例。我将用户包括在内,以防您需要所有用户,而不仅仅是fu中的一个用户