2017-09-05 1 views
5

소셜 네트워크 추적 응용 프로그램에서 작업 중입니다. 조인조차도 적절한 인덱싱으로 올바르게 작동합니다. 하지만 order by 절을 추가하면 총 쿼리 실행 시간이 100 배 길어집니다. order by 절없이 twitter_users를 가져 오는 데 사용한 다음 쿼리.mysql에서 조인을 사용하여 성능을 향상시키는 방법

SELECT DISTINCT `tracked_twitter`.id 
FROM tracked_twitter 
INNER JOIN `twitter_content` ON `tracked_twitter`.`id` = `twitter_content`.`tracked_twitter_id` 
INNER JOIN `tracker_twitter_content` ON `twitter_content`.`id` = `tracker_twitter_content`.`twitter_content_id` 
AND `tracker_twitter_content`.`tracker_id` = '88' 
LIMIT 20 

보기 행은 0-19

(20 총, 쿼리 0.0714 초를했다)하지만 (인덱스 컬럼) 조항에 의해

SELECT DISTINCT `tracked_twitter`.id 
FROM tracked_twitter 
INNER JOIN `twitter_content` ON `tracked_twitter`.`id` = `twitter_content`.`tracked_twitter_id` 
INNER JOIN `tracker_twitter_content` ON `twitter_content`.`id` = `tracker_twitter_content`.`twitter_content_id` 
AND `tracker_twitter_content`.`tracker_id` = '88' 
ORDER BY tracked_twitter.followers_count DESC 
LIMIT 20 

보기 행을 순서를 추가 할 때 0-19 ((20) 총 쿼리 13.4636 초)

enter image description here

을 EXPLAIN했다

- : 19 (총 20은, 쿼리 0.0711 초를했다) 68,236,387 10,525,612 팔로어 -] 나는 그것이 0

SELECT * FROM `tracked_twitter` WHERE 1 order by `followers_count` desc limit 20 

보기 행 많은 시간을 고려하지 않습니다 만의 테이블에 ORDER BY 절을 구현

같은 테이블 작성 쿼리는 다음과

CREATE TABLE IF NOT EXISTS `tracked_twitter` (
    `id` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 
    `handle` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 
    `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 
    `location` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, 
    `description` text COLLATE utf8_unicode_ci, 
    `profile_image` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 
    `followers_count` int(11) NOT NULL, 
    `is_influencer` tinyint(1) NOT NULL DEFAULT '0', 
    `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', 
    `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', 
    `gender` enum('Male','Female','Other') COLLATE utf8_unicode_ci 
    DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    KEY `followers_count` (`followers_count`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 

그래서 나는 그것의 테이블에 그것을 실행할 때 잘 작동하여 쿼리 및 주문을 느리게하지 않았다 가입 할 수 있습니다. 그렇다면 성능을 어떻게 향상시킬 수 있습니까? 나만 상위 테이블에서 결과 집합이 필요한 경우

UPDATE 1

@GordonLinoff 방법은 해결한다. 1 인당 숫자 트윗을 알고 싶습니다 (tracked_twitter 테이블과 일치하는 twitter_content 수). 어떻게 수정할 수 있습니까? 그리고 만약 내가 짹짹 콘텐츠에 수학 함수를 갖고 싶다면 어떻게해야합니까 ??

SELECT `tracked_twitter` . * , COUNT(*) AS twitterContentCount, retweet_count + favourite_count + reply_count AS engagement 
FROM `tracked_twitter` 
INNER JOIN `twitter_content` ON `tracked_twitter`.`id` = `twitter_content`.`tracked_twitter_id` 
INNER JOIN `tracker_twitter_content` ON `twitter_content`.`id` = `tracker_twitter_content`.`twitter_content_id` 
WHERE `is_influencer` != '1' 
AND `tracker_twitter_content`.`tracker_id` = '88' 
AND `tracked_twitter_id` != '0' 
GROUP BY `tracked_twitter`.`id` 
ORDER BY twitterContentCount DESC 
LIMIT 20 
OFFSET 0 
+0

'LIMIT' 절을 제거하면 정렬되지 않은 쿼리가 얼마나 오래 걸릴까요? 정렬되지 않은 결과 세트의 'LIMIT'은 기본적으로 "내 기준과 일치하는 20 개의 레코드를 가져옵니다"라는 의미입니다. 반면에 정렬 된 결과에서 "내 기준과 일치하는 처음 20 개의 레코드를 얻으십시오"라는 의미입니다. 기본적으로 모든 것을 식별해야 함을 의미합니다. 그들의. –

+0

쿼리에서'EXPLAIN'의 결과는 무엇입니까? – raina77ow

+0

@ raina77ow 문제의 설명 그림을 추가했습니다. – Tamizharasan

답변

3

distinct을 제거하십시오. 그것은 성능 희생자입니다. 왜 첫 번째 쿼리가 빠르게 작동하는지 모르겠습니다. 아마도 MySQL은 그것을 최적화하기에 충분히 똑똑 할 것입니다. 내가 시도 할 것

: tracked_twitter(followers_count, id), twitter_content(tracked_twitter_id, id)tracker_twitter_content(twitter_content_id, tracker_id) :이 버전의

SELECT tt.id 
FROM tracked_twitter tt 
WHERE EXISTS (SELECT 1 
       FROM twitter_content tc INNER JOIN 
        tracker_twitter_content ttc 
        ON tc.id = ttc.twitter_content_id 
       WHERE ttc.tracker_id = 88 AND 
        tt.id = tc.tracked_twitter_id 
      ) 
ORDER BY tt.followers_count DESC ; 

, 당신은에 인덱스를 원한다.

+0

완벽하게 작동하고 order by 절은 쿼리 실행 속도를 늦추지 않았습니다 (총 20 개, 쿼리 소요 시간) 0.0707 초). 당신이 그 질문을 설명하면 나는 기뻐할 것입니다. 그래서 나는이 접근에 대한 지식을 얻을 것입니다. 그리고 이러한 접근법에 대한 참고 링크가 있다면 유용 할 것입니다. 귀하의 답변에 감사드립니다. – Tamizharasan

+0

첫 번째 쿼리가 빠르게 작동한다고 가정합니다. MySQL은 정렬되지 않은 집합에서 20 개의 별개 레코드를 수집해야한다는 것을 알고 있기 때문입니다. 낮은 수의 행 (20 개 이상 1000 개 미만이라고 가정)에서 오는 것입니다. 주문한 수백만 개의 항목과 처음 20 개의 항목을 구하는 것은 훨씬 느립니다. 별개의 빨간 청어와 약간의 시간이 걸리는 orderby입니다. 아니면 MySQL이 명령뿐만 아니라 멍청한 상태 일 수도 있습니다. 그 다음으로 수백만 줄의 뚜렷한 행을 반환하기 전에 20 –

+0

@CaiusJard. . . 사실, MySQL은 중복을 방지하기 위해 인덱스를 'id'에 사용할 수 있다고 생각합니다. 인덱스를 순서대로 읽는 것입니다. 명시적인'ORDER BY'로는 불가능합니다. –

1

부모 테이블은 제한 가장 큰 문제는 상대적으로 적은 행이 있더라도, 당신은 (대신 정수) 기본 키로 따라서에서 외부 키로 varchar(255) COLLATE utf8_unicode_ci 사용한다는 것입니다

SELECT DISTINCT `tracked_twitter`.id FROM 
(SELECT id,followers_count FROM tracked_twitter ORDER BY followers_count DESC 
LIMIT 20) AS tracked_twitter 
INNER JOIN `twitter_content` ON `tracked_twitter`.`id` = `twitter_content`.`tracked_twitter_id` 
INNER JOIN `tracker_twitter_content` ON `twitter_content`.`id` = `tracker_twitter_content`.`twitter_content_id` 
AND `tracker_twitter_content`.`tracker_id` = '88' 
ORDER BY tracked_twitter.followers_count DESC 
+0

대답이 될 수 없습니다. order by 절에서 다른 테이블 제약을 고려하지 않았기 때문입니다. 따라서 상위 테이블에서 20 레코드 만 가져 와서 다른 테이블과 조인합니다. 나는 쿼리를 실행할 때 단 두 줄만 가져 왔습니다. – Tamizharasan

1

브라켓 계속 다른 테이블. 내가 의심하는 동일한 문제는 twitter_content.id입니다. 이로 인해 많은 긴 문자열 비교가 발생하고 임시 테이블에 대한 추가 메모리가 많이 예약됩니다.

쿼리 자체에 대해서는 예, followers_count 인덱스를 따라 이동하여 관련 테이블의 조건을 확인하는 쿼리 여야합니다. Gordon Linoff가 제안했거나 색인 힌트를 사용하여이 작업을 수행 할 수 있습니다.

관련 문제