하위 쿼리를 사용하는 SQL 쿼리는 두 쿼리를 개별적으로 사용하는 것보다 더 오래 걸립니다.
문제
저는 두 가지 질문이 있는데 하나는 다른 하나의 결과가 필요합니다.제 첫 번째 추측은 독립적인 하위 쿼리를 사용하는 것이었습니다.
SELECT P2.*
FROM ExampleTable P2
WHERE P2.delivery_start >= (
SELECT MIN(P1.delivery_start)
FROM ExampleTable P1
WHERE 1641288602 < P1.delivery_end
);
전체 쿼리 시간은 5-6초 정도 소요되며, 이는 제 애플리케이션에 너무 긴 시간입니다.이러한 쿼리를 차례로 실행하는 데 걸리는 시간은 다음 두 가지 모두 약 800ms입니다.
SELECT MIN(P1.delivery_start)
FROM ExampleTable P1
WHERE 1641288602 < P1.delivery_end;
SELECT P2.*
FROM ExampleTable P2
WHERE P2.delivery_start >= 1641286800;
Mariadb 10.2를 사용하고 있으며 두 가지 모두에 대한 인덱스가 있습니다.delivery_start그리고.delivery_end.
내가 시도한 것
하위 쿼리 대신 CTE를 사용하여 동일한 성능을 제공했습니다.변수 사용SET는 두 쿼리를 개별적으로 실행하는 것과 유사한 결과를 제공하므로 당분간 사용할 것입니다.
도망친EXPLAIN세 개의 쿼리 모두에서:
하위 쿼리를 사용한 쿼리
| 이드 | select_type | 테이블 | 유형 | possible_key | 열쇠 | key_len | 심판을 보다 | 행들 | 추가의 |
|---|---|---|---|---|---|---|---|---|---|
| 1 | 기본적인 | P2 | 모든. | 배달_시작 | NULL | NULL | NULL | 6388282 | 사용 위치 |
| 2 | 하위 쿼리 | P1 | 범위 | 배달_끝 | 배달_끝 | 4 | NULL | 36378 | 인덱스 조건 사용 |
개별 쿼리
| 이드 | select_type | 테이블 | 유형 | possible_key | 열쇠 | key_len | 심판을 보다 | 행들 | 추가의 |
|---|---|---|---|---|---|---|---|---|---|
| 1 | 간단하죠. | P1 | 범위 | 배달_끝 | 배달_끝 | 4 | NULL | 36432 | 인덱스 조건 사용 |
| 이드 | select_type | 테이블 | 유형 | possible_key | 열쇠 | key_len | 심판을 보다 | 행들 | 추가의 |
|---|---|---|---|---|---|---|---|---|---|
| 1 | 간단하죠. | P2 | 범위 | 배달_시작 | 배달_시작 | 4 | NULL | 35944 | 인덱스 조건 사용 |
질문.
저는 그 문제가 첫 번째에 있다고 생각합니다.EXPLAIN활자가 있는 테이블ALL즉, 데이터베이스가 전체 테이블 검색을 수행합니다.제 질문은 단순합니다: 왜죠?옵티마이저가 서브쿼리가 우리가 필요로 하는 숫자를 생성한다는 것을 알아낼 수 없습니까?range유형 쿼리?그리고 왜 색인을 사용하지 않습니까?
이 문제는 MariaDB 문서에 설명되어 있습니다.
나머지 모든 경우 NULL을 FALSE로 대체할 수 없는 경우 인덱스 조회를 사용할 수 없습니다.이는 서버의 제한이 아니라 ANSI SQL 표준의 NULL 의미론의 결과입니다.
전체 검사는 여기에서 이루어집니다. https://mariadb.com/kb/en/non-semi-join-subquery-optimizations/
하위 쿼리 결과는 행을 찾을 수 없는 경우 NULL을 반환할 수 있습니다.따라서 MariaDB는 상위 쿼리에 인덱스를 사용할 수 없습니다.
항상 NULL이 아닌 스칼라가 있는 행을 반환하거나 두 개의 개별 쿼리가 있는 스틱을 반환하는 방식으로 하위 쿼리를 다시 작성해야 합니다.그러나 첫 번째 쿼리가 NULL을 반환하면 어떻게 됩니까?복합 문을 사용하면 두 번째 쿼리 주위에 if를 배치하고 첫 번째 쿼리가 NULL을 반환하는 경우 실행하지 않을 수 있습니다.
교체
INDEX(delivery_start)
INDEX(delivery_end)
다음을 사용합니다.
INDEX(delivery_start, delivery_end)
INDEX(delivery_end, delivery_start)
두 번째 것은 하위 질의에 상당히 도움이 될 것입니다.그러면 첫 번째 질문이 외부 질의에 도움이 될 수 있습니다.
도움이 , (이되않추오시도십하가으면지움▁(오▁(도▁add시▁please십추하가▁don▁those,되않)를 추가해 주십시오.)SHOW CREATE TABLE,EXPLAIN SELECT ...테이블 크기).
언급URL : https://stackoverflow.com/questions/70596164/sql-query-with-subquery-takes-longer-than-both-queries-separately
'programing' 카테고리의 다른 글
| 리포지토리의 모든 위치에서 ipython 노트북 체크포인트를 무시하는 방법 (0) | 2023.07.11 |
|---|---|
| HTTPS에 대한 W3 총 캐시 페이지는 '고유하게' 무엇을 의미합니까? (0) | 2023.07.11 |
| Git 저장소에서 선택한 커밋 로그 항목을 변경 사항을 유지하면서 제거하는 방법은 무엇입니까? (0) | 2023.07.11 |
| 파이어베이스(FCM): 액티비티 열기 및 알림 클릭 시 데이터 전달. 안드로이드 (0) | 2023.07.11 |
| 마스터 푸시에서 Git 트리거를 사용하여 젠킨스 CI를 만들려면 어떻게 해야 합니까? (0) | 2023.07.11 |