周末推出趋势数据WeeK

时间:2014-02-24 17:08:06

标签: mysql

我试图在一周内扣除一些金额,我建立的查询得到的数据,但是非常慢。

 SELECT app_client_id
 , (SELECT COUNT(b.app_id) FROM `li_appointments` AS b
         WHERE YEARWEEK(b.app_datetime) = YEARWEEK(DATE_ADD(NOW(),INTERVAL -1 WEEK))
         AND b.app_client_id = a.app_client_id)
 , (SELECT COUNT(b.app_id) FROM `li_appointments` AS b
         WHERE YEARWEEK(b.app_datetime) = YEARWEEK(DATE_ADD(NOW(),INTERVAL -2 WEEK))
         AND b.app_client_id = a.app_client_id)
 FROM `li_appointments` AS a

EXPLAIN给了我这个:

 |id||select_type       ||table||type ||possible_keys||key  ||key_len||ref||rows ||Extra    |
 |1 ||PRIMARY           ||a    ||index|\N             |Extra||18      |\N  |61901||Using index|
 |3 ||DEPENDENT SUBQUERY||b    ||index|\N             |Extra||18      |\N  |61901||Using where; Using index|
 |2 ||DEPENDENT SUBQUERY||b    ||index|\N             |Extra||18      |\N  |61901||Using where; Using index|

正在引用的表是:

 create table `li_appointments` (
`app_id` int (11),
`app_datetime` datetime ,
`app_facility` varchar (600),
`app_department` varchar (600),
`app_address` varchar (600),
`app_language` varchar (600),
`app_requesting_person` varchar (600),
`app_service_provider` varchar (600),
`app_client_id` int (11),
`app_client_other` varchar (600),
`app_medicaid_status` int (11),
`app_health_program` varchar (150),
`les_name` varchar (500),
`les_dob` varchar (75),
`les_medicaid_id` varchar (500),
`billing_total_time` time ,
`billing_workorder_received` int (11),
`billing_admin_fee` float ,
`billing_notes` varchar (3000),
`app_notes` varchar (3000),
`created_by` varchar (300),
`created_on` datetime ,
`modified_by` varchar (300),
`modified_on` datetime ,
`wo_entered_by` varchar (300),
`app_callback_num` varchar (135),
`terp_id` varchar (135),
`app_covered_by` varchar (135),
`covered_on` datetime ,
`uofu_csn` varchar (135)); 

有没有更好的方法来获取这些数据?

3 个答案:

答案 0 :(得分:1)

这可能很慢,因为你所有的WHERE子句都使用像YEARWEEK(b.app_datetime)这样的东西来阻止使用索引以及你正在使用子选择这一事实。

我真的不明白你为什么要使用子选择。一个简单的案例陈述应该消除这种需要:

SELECT
    app_client_id,
    SUM(
        CASE
            WHEN app_datetime > DATE_ADD(NOW(),INTERVAL -1 WEEK) THEN 1
            ELSE 0
        END
    ) AS last_week_count,
    SUM(
        CASE
            WHEN app_datetime > DATE_ADD(NOW(),INTERVAL -1 WEEK) THEN 0
            WHEN app_datetime > DATE_ADD(NOW(),INTERVAL -2 WEEK) THEN 1
            ELSE 0
        END
    ) AS two_weeks_ago_count    
FROM `li_appointments`
GROUP BY app_client_id

确保您在app_client_id上有索引。

还应该注意,这将提供每周滚动数据集。在您的原始问题中,您使用的YEARWEEK()可能实际上一次提供超过一周的数据。例如,假设它是星期三,我想计算YEARWEEK()等于上周三的所有项目。这实际上会匹配SUN / MON到前一周的SAT / SUN的所有项目(周开始和结束,具体取决于MySQL运行的模式与周编号有关)。

如果这实际上是你想要的,那就更容易实现:

SELECT
    app_client_id,
    YEARWEEK(app_datetime) AS year_week,
    SUM(1) as weekly_count   
FROM `li_appointments`
GROUP BY `app_client_id`, `year_week`
HAVING `year_week` < YEARWEEK(NOW())
ORDER BY `year_week` DESC
LIMIT 2

这将为您提供过去两周的数据,但不是当前周。如果您想要当前周(可能长达6天,长度为23:59:59),只需删除HAVING条款。

答案 1 :(得分:0)

将子查询更改为如下所示加入,看看它是否提高了性能

SELECT 
a.app_client_id,
COUNT(b.app_id) as appid_count
from app_client_id a join
li_appointments b on b.app_client_id = a.app_client_id
where 
YEARWEEK(b.app_datetime) in 
   (
   (YEARWEEK(DATE_ADD(NOW(),INTERVAL -1 WEEK)),
   (YEARWEEK(DATE_ADD(NOW(),INTERVAL -2 WEEK))
   )

答案 2 :(得分:0)

您可能想尝试使用UNION ALL设置的子查询:

SELECT app_client_id
    ,SUM(app_id_count_1_week) AS app_id_count_1_week
    ,SUM(app_id_count_2_weeks) AS app_id_count_2_weeks
FROM (
    SELECT app_client_id
        ,COUNT(app_id) AS app_id_count_1_week
        ,CAST(0 AS INTEGER) AS app_id_count_2_weeks
    FROM li_appointments
    WHERE b.app_datetime >= CURRENT_DATE - INTERVAL '7' DAY
    GROUP BY app_client_id
    UNION ALL
    SELECT app_client_id
        ,CAST(0 AS INTEGER) AS app_id_count_1_week
        ,COUNT(app_id) AS app_id_count_2_weeks
    FROM li_appointments
    WHERE b.app_datetime >= CURRENT_DATE - INTERVAL '14' DAY
    GROUP BY app_client_id
) AS Both_Counts
GROUP BY app_client_id

这将根据需要单独进行聚合,UNION结果,然后顶层的SUM将添加实际的COUNT和0.语法的更改是使WHERE子句符合ANSI标准。

只是一个想法。