답변:
LIMIT성능 향상 을 활용 하려면 다음이 필요합니다.
LIMIT전에 사용JOIN이러한 원칙을 조정하면 먼 길을 갈 수 있습니다.
이 YouTube 비디오 를 보면서 이러한 개념을 배웠습니다 (프랑스어 악센트를 통해주의 깊게 듣기)
이 개념을 사용하여 일부 테이블에서 상위 40 개 기사를 얻는 방법에 대한 매우 까다로운 StackOverflow 질문에 대답했습니다. 2011 년 5 월 12 일 : 조인 테이블에서 단일 행 가져 오기 .
에서 그 질문에 대한 내 대답 (5 월 (16), 2011) , 나는 다음과 같은 쿼리를 작성하고 철저하게 테스트 :
SELECT
AAA.author_id,
AAA.date_created,
IFNULL(BBB.title,'<NO_TITLE>') title,
IFNULL(CCC.filename,'<NO-IMAGE>') filename,
IFNULL(CCC.date_added,'<NO-IMAGE-DATE>') image_date
FROM
(
SELECT
AA.id,
AA.date_added,
BB.author_id,
BB.date_created
FROM
(
SELECT
A.id,IFNULL(MAX(B.date_added),'1900-01-01 00:00:00') date_added
FROM (SELECT id FROM articles ORDER BY date_created DESC LIMIT 40) A
LEFT JOIN article_images B ON A.id = B.article_id
GROUP BY A.id
) AA
INNER JOIN articles BB USING (id)
) AAA
LEFT JOIN article_contents BBB ON AAA.id=BBB.article_id
LEFT JOIN article_images CCC
ON (AAA.id=CCC.article_id AND AAA.date_added=CCC.date_added)
ORDER BY AAA.date_created DESC;
검색어와 함께 줄을 확인하십시오 LIMIT
FROM (SELECT id FROM articles ORDER BY date_created DESC LIMIT 40) A
이 하위 쿼리는 3 단계 깊이에 묻혀 있습니다. 이것으로을 사용하여 마지막 40 기사를 얻을 수있었습니다 LIMIT. 그런 다음 필요한 JOIN을 수행했습니다.
LIMIT색인의 카디널리티, 데이터 컨텐츠 및의 결과 세트 크기로 인해 서브 쿼리 내부를 수행하는 것이 항상 답이되는 것은 아닙니다 LIMIT. "행에 멍청이"가 있다면 (질문에 네 가지 원칙을 염두에 두어야 함) 놀랍게도 좋은 결과를 얻을 수 있습니다.LIMIT키만 수집 하여 가능한 한 간단하게 쿼리를 작성하십시오 .(A [LEFT] JOIN B) LIMIT 100동일하다 (A LIMIT 100) [LEFT] JOIN (B LIMIT 100)? 어디 [LEFT] JOIN외부 또는 내부 수단에 가입
(A LIMIT 100) [LEFT] JOIN B합니다. 아이디어는 LIMIT가능한 빨리 결과 세트의 크기를 결정하는 데 사용 됩니다. 왼쪽의 키 순서를 유지하기 때문에 LEFT JOIN대신 사용 합니다 . INNER JOINLEFT JOIN
(A LEFT JOIN B) GROUP BY A.pk LIMIT 100작성됩니다. 일반적으로 다음과 같이 다시 작성할 수 있습니다 (A LIMIT 100) LEFT JOIN B GROUP BY A.pk(내부 조인이 없으면 내부 조인이 같지 않습니다). 롤란도의 예는 정확히 그런 경우입니다.
쿼리가 실행되면 먼저 여러 연산자로 구성된 계획으로 변환됩니다. 두 가지 기본 유형의 연산자가 있습니다 : 차단 및 비 차단. 비 차단 연산자는 요청 된 각 행에 대해 해당 자식 또는 자식에서 행 (또는 몇 개의 행)을 검색합니다. 반면에 차단 연산자는 출력을 생성하기 전에 모든 하위의 전체 행 세트를 읽고 처리해야합니다.
정렬은 일반적인 차단 연산자입니다. 따라서 order by를 사용하는 선택은 한계에서 큰 이점을 얻지 못합니다. 그러나 메모리가 덜 필요하고 limit 절이 제공 될 때 더 빠른 정렬 알고리즘을 사용할 수있는 RDBMS가 있습니다. 이 경우 현재 첫 번째 n 행을 저장하고 이전 행이 나올 때 메모리에서 옮기는 것으로 충분합니다. 이는 상당한 성능 향상이 될 수 있습니다. 그러나 MySQL이 그 능력을 가지고 있는지 100 % 확신하지 못합니다.
어느 쪽이든, 제한 정렬조차도 첫 번째 출력 행을 생성하기 전에 전체 입력 행 세트를 처리해야합니다. 이 알고리즘을 구현하면 정렬 속도를 높일 수 있지만 나머지 쿼리가 가장 비싼 경우 전체 실행 시간은 제공된 제한으로 인해 크게 향상되지 않습니다.
GROUP BY차단 연산자를 포함하지 않는 계획으로 이어질 수 있습니다.
제 경우에는 (아직도) 왜 이해가 안 되더라도 예 라고 말할 수 있습니다 .
SELECT g0_.id AS id_0, COUNT(a1_.id_tarifs) AS sclr_1
FROM groupe_jardinerie g0_
INNER JOIN articles_tarifs a1_
ON (a1_.groupe_jardinerie_id = g0_.id)
WHERE g0_.centrale_id = 511
AND a1_.date_fin_tarif >= '2018-01-29 10:46:35'
GROUP BY g0_.id;
(result set)
8 rows in set (**18.14 sec**)
시간은 18 초입니다. 큰 LIMIT와 동일한 요청 :
SELECT g0_.id AS id_0, COUNT(a1_.id_tarifs) AS sclr_1
FROM groupe_jardinerie g0_
INNER JOIN articles_tarifs a1_
ON (a1_.groupe_jardinerie_id = g0_.id)
WHERE g0_.centrale_id = 511
AND a1_.date_fin_tarif >= '2018-01-29 10:46:35'
GROUP BY g0_.id
LIMIT 100000000000;
(exact same result set)
8 rows in set (**1.32 sec**)
10 배 이상 빠르다 !!!
EXPLAIN은 두 요청 모두에 대해 동일한 결과를 제공합니다.
+----+-------------+-------+------------+--------+---------------------------------------------------+---------+---------+------------------------------+--------+----------+----------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+--------+---------------------------------------------------+---------+---------+------------------------------+--------+----------+----------------------------------------------+
| 1 | SIMPLE | a1_ | NULL | ALL | IDX_438010BBC10784EF | NULL | NULL | NULL | 795135 | 33.33 | Using where; Using temporary; Using filesort |
| 1 | SIMPLE | g0_ | NULL | eq_ref | PRIMARY,IDX_9CA5CF6758A1D71F,IDX_9CA5CF67670C757F | PRIMARY | 4 | phs.a1_.groupe_jardinerie_id | 1 | 50.00 | Using where |
+----+-------------+-------+------------+--------+---------------------------------------------------+---------+---------+------------------------------+--------+----------+----------------------------------------------+
LIMIT는 결과 세트를 제한하기 위해서만 간섭해야합니다 (즉, LIMIT 4를 수행하는 경우 위 결과 세트의 처음 4 행만 얻습니다).
LIMIT. 첫 번째 쿼리는 18 초 안에 실행되어 결과 집합을 제공합니다. 두 번째 쿼리의 모든 데이터는 첫 번째 쿼리로 인해 InnoDB 버퍼 풀에 이미 캐시되어 있으므로 물론 mysql을 다시 시작하더라도 첫 번째 쿼리를 실행하고 mysql을 다시 시작하고 두 번째 쿼리를 실행하더라도 두 번째 쿼리는 더 빨라야합니다. 쿼리와 동일한 결과를 얻습니다. . 더 나은 결과를 LIMIT얻으 려면 1) LIMIT이전 JOIN, 2) 정렬 순서로 제한 ASC또는 DESC.
LIMIT효율성 을 향상시키는 경우를 위해 이것을 읽는 것이 좋습니다 : LIMIT 쿼리 최적화