programing

Mysql 하위 선택이 매우 느립니다.

stoneblock 2023. 9. 26. 21:57

Mysql 하위 선택이 매우 느립니다.

저는 이런 테이블이 있습니다.

-------------------------------
| id | valid_until |  username|
-------------------------------
| 1  | 2020-01-01  |   user1  |
-------------------------------  
| 1  | 2020-01-01  |   user2  |
-------------------------------  
| 1  | 2020-01-02  |   user3  |
-------------------------------  
| 1  | 2020-01-02  |   user4  |
-------------------------------  
| 1  | 2020-01-03  |   user5  |
-------------------------------  
| 1  | 2020-01-03  |   user6  |
-------------------------------  
| 1  | 2020-01-03  |   user7  |
-------------------------------  

이것이 사용자 등록 테이블입니다.valid_until구독이 종료되는 시점을 나타냅니다.

매일 활성 구독을 알고 싶어서 범위가 있습니다. 예를 들어,2020-01-01로.2020-01-03제 질문은 이렇습니다.

SELECT 
    valid_until qva,
    (SELECT 
            COUNT(iod.id) AS ct
        FROM
            `order_detail` iod
        WHERE
            valid_until > qva)
FROM
    `order_detail`
WHERE
    valid_until >= '2020-01-01'
        AND valid_until <= '2020-01-03'
GROUP BY qva

하지만 이 쿼리가 너무 느립니다. 내 쿼리에 무슨 문제가 있습니까?응답시간(230초)

SQL 표준에 따라 쿼리가 잘못되었습니다.당신은 가지고 있다GROUP BY qva(그리고 여기서 별칭 이름을 사용하는 것은 일반적으로 허용되지 않지만 MySQL 및 MariaDB에서는 허용됨) 그러나 하위 쿼리 결과에는 집계 함수를 적용하지 않습니다.MySQL은 표준을 위반한 것으로 알려져 있으며 이들은 묵묵히 적용됩니다.ANY_VALUE이런 비집고적인 표현으로

이렇게 하면 쿼리 속도가 느려집니다.날짜 범위의 각 순서에 대해 카운트를 평가하고 맨 끝에 있는 날짜당 카운트 중 하나만 선택합니다.

그럼 처음부터 다시 쿼리를 만들어 보겠습니다.지정된 날짜 범위에서 각 날짜에 대해 하나의 결과 행을 사용하려고 합니다.즉,

select distinct valid_until
where valid_until between date '2020-01-01' and date '2020-01-03'
from order_detail;

그런 다음 이 날짜마다 카운트를 구합니다.원래 쿼리와 같이 하위 쿼리에서 이 작업을 수행할 수 있습니다.제 생각에는 그럴 것 같습니다.>=대신에>하지만 그날 하루까지 유효한 주문(또는 적어도 이것이 내가 예상했던 것입니다).

SELECT 
  dates.day,
  (
    select count(*) 
    from order_detail od
    where od.valid_until >= dates.day
  ) as ct
FROM
(
  select distinct valid_until as day
  where valid_until between date '2020-01-01' and date '2020-01-03'
  from order_detail
) dates
order by dates.day;

(이것은 다음을 가정합니다.valid_until단순한 데이트일 뿐입니다.날짜 시간이면 이 쿼리를 조금 조정해야 합니다.)

업데이트:

요청 주석에서 ysth가 알려준 것처럼 쿼리는 다음과 같이 존재하는 주어진 범위의 일만을 얻을 수 있습니다.valid_until당신 테이블에.저도 그렇습니다.상관없이 3일을 원한다면 하위 쿼리를 교체하고 테이블에서 독립적으로 만들어야 합니다.

FROM
(
  select date '2020-01-01' as day union all
  select date '2020-01-02' as day union all
  select date '2020-01-03' as day
) dates

내 생각엔 당신은 단지 당신이 원하는 것은valid_until최신 날짜부터 가장 빠른 날짜까지:

select valid_until, count(*) day_count,
       sum(count(*)) over (order by valid_until desc) as count_as_of_day
from order_details od
group by valid_until;

날짜 범위에 대해 원하는 경우 하위 쿼리를 사용합니다.

select od.*
from (select valid_until, count(*) day_count,
             sum(count(*)) over (order by valid_until desc) as count_as_of_day
      from order_details od
      group by valid_until
     ) od
where valid_until >= :from and valid_until <= :to

언급URL : https://stackoverflow.com/questions/63868917/mysql-sub-select-is-very-slow