큰 쿼리를 여러 개의 작은 쿼리로 분리하는 것이 더 낫습니까?


13

원하는 결과를 얻기 위해 여러 테이블을 sub select 문과 함께 여러 테이블을 조인해야하는 상황이 있습니다.

내 질문은, 여러 개의 작은 쿼리를 사용하고 DB를 두 번 이상의 호출로 쿼리하여 논리적 작업을 응용 프로그램 계층으로 가져와야합니까?
예를 들어 다음 쿼리를 고려하십시오.

SELECT *
FROM   `users`
WHERE  `user_id` IN (SELECT f2.`friend_user_id`
                     FROM   `friends` AS f1
                            INNER JOIN `friends` AS f2
                              ON f1.`friend_user_id` = f2.`user_id`
                     WHERE  f2.`is_page` = 0
                            AND f1.`user_id` = "%1$d"
                            AND f2.`friend_user_id` != "%1$d"
                            AND f2.`friend_user_id` NOT IN (SELECT `friend_user_id`
                                                            FROM   `friends`
                                                            WHERE  `user_id` = "%1$d"))
       AND `user_id` NOT IN (SELECT `user_id`
                             FROM   `friend_requests`
                             WHERE  `friend_user_id` = "%1$d")
       AND `user_image` IS NOT NULL
ORDER  BY RAND() 
LIMIT %2$d

가장 좋은 방법은 무엇입니까?

답변:


14

여기에서 datagod를 사용하여 크고 복잡한 쿼리에 동의하지 않습니다. 나는 그들이 조직화되지 않은 경우에만 문제로 본다. 성능 측면에서 볼 때 플래너는 정보 검색 방법에 대해 훨씬 더 많은 자유를 가지기 때문에 거의 항상 더 좋습니다. 그러나 유지 관리 성을 염두에두고 큰 쿼리를 작성해야합니다. 일반적으로, 단일 쿼리가 200 개 이상의 행에 대해 진행되는 경우에도 간단하고 체계적인 SQL을 쉽게 디버깅 할 수 있다는 것을 알았습니다. 이것은 일반적으로 어떤 종류의 문제를 다루고 있는지 잘 알고 있기 때문에 쿼리에서 확인해야 할 영역이 거의 없기 때문입니다.

유지 관리 문제인 IME는 SQL 구조가 손상 될 때 발생합니다. 하위 선택의 길고 복잡한 쿼리는 인라인 뷰와 마찬가지로 가독성과 문제 해결에 악영향을 미치며, 긴 쿼리에서는 두 가지를 모두 피해야합니다. 대신 가능한 경우 VIEW를 사용하고 (MySQL에서는 뷰가 모든 것을 잘 수행하지 않지만 대부분의 다른 DB에서는 수행합니다), 작동하지 않는 공통 테이블 표현식을 사용하십시오 (MySQL은 이들을 지원하지 않습니다) btw).

길고 복잡한 쿼리는 where 절을 단순하게 유지 관리하는 성능 및 유지 관리 사례와 하위 선택 대신 조인을 사용하여 최대한 많은 작업을 수행 할 수 있습니다. 목표는 "레코드가 표시되지 않도록"쿼리에서 확인할 특정 위치를 제공하는 것입니다 (조인에서 삭제되거나 where 절에서 필터링 되었습니까?). 실제로 물건을 유지할 수 있습니다.

확장성에 관해서는 플래너의 유연성이 높을수록 좋은 것입니다.

편집 : 이것은 MySQL이라고 언급하므로 뷰가 제대로 수행되지 않을 가능성이 높으며 CTE는 의심의 여지가 없습니다. 또한 주어진 예제는 특별히 길거나 복잡하지 않으므로 문제가되지 않습니다.


참고 : 생성 된 쿼리 계획이 최적화되지 않을 정도로 길고 복잡한 쿼리 (MySQL은 아니지만 여전히 ...)가 있습니다. 이 경우 실제로 매우 복잡한 쿼리 하나를 덜 복잡한 쿼리 두 개로 나누면 더 빠른 결과를 얻을 수 있습니다. 즉, 드문 일이며, 일반적으로 복잡한 쿼리를 작성하고 쿼리를 미리 작은 덩어리로 나누지 않고 문제가 있는지 알아 보겠습니다.
RDFozz

8

이 크고 복잡한 쿼리를 지원 / 정리해야하는 사람으로서 이해하기 쉬운 여러 개의 작은 덩어리로 나누는 것이 훨씬 낫습니다. 성능 관점에서 반드시 더 나을 필요 는 없지만 최소한 SQL에 좋은 쿼리 계획을 제시 할 수있는 더 좋은 기회를 제공하고 있습니다.

당신을 따르는 사람들의 삶을 편하게 만들어라. 그러면 그들은 당신에 대해 좋은 말을 할 것이다. 그들을 힘들게하면 그들은 당신을 저주 할 것이다.


2
간단한 쿼리 문자열의 단점은 상태에 따라 상태가 크게 변경되어 응용 프로그램의 전체 디버깅이 더 복잡해진다는 것입니다. 즉, 큰 SQL 쿼리를 트리로 자주 디버깅 할 수 있지만 응용 프로그램 코드는 명령문의 상태 변경 방법을 확인하여 명령문을 디버깅합니다. 실제 문제는 하위 선택과 인라인 뷰가 자체 트리라는 사실과 관련이 있습니다 ...
Chris Travers

필자의 경우 DB와 코드를 관리 해야하는 유일한 사람은 나 자신입니다. 그리고 주로 제 질문은 성능 포인트 쿼리에 관한 것이 었습니다.
Hamed Momeni 2018

너희들은 내가 큰 배치 프로세스를 작성하는 방식을 살펴 봐야 할 것이다. 읽기 쉬운 간단한 쿼리로 분류하십시오. 정리하려고하는 쿼리가 일반적으로 1000 줄 이상이기 때문에 편견이 있습니다.
datagod

5

2 개의 키워드 쿼리 성능 및 확장성에 대한 나의 2 센트 :

쿼리 성능 : SQL Server 병렬 처리는 이미 쿼리를 다중 스레드 검색으로 분류하는 작업이 매우 훌륭하므로 SQL Server에 대해 쿼리 성능을 얼마나 향상 시킬지 잘 모르겠습니다. 그러나 실행 계획을 검토하여 실행할 때 어느 정도의 병렬 처리를 수행하는지 확인하고 결과를 두 가지 방식으로 비교해야합니다. 동일하거나 더 나은 성능을 얻기 위해 쿼리 힌트를 사용해야하는 경우 나중에 쿼리 힌트가 최적이 아닐 수 있으므로 IMO를 사용할 가치가 없습니다.

확장 성 : datagod가 언급 한대로 쿼리를 읽는 것이 더 쉬울 수 있으며 다른 영역에서도 새 쿼리를 사용할 수 있지만 다른 호출에도 사용하지 않을 경우 별도의 쿼리로 나누는 것이 좋습니다. 하나의 작업을 관리하는 데 더 많은 저장 프로세스가 필요하며 IMO는 확장성에 기여하지 않습니다.


2
RE : OP가 특정 RDBMS를 지정하지 않았지만 "SQL Server"참조. 백틱에서 MySQL에 있다고 의심되는 경우LIMIT
Martin Smith

@MartinSmith 당신은 올바르게 의심합니다. MySQL입니다.
Hamed Momeni

2

때로는 큰 / 복잡한 쿼리를 작은 쿼리로 나누는 것 외에는 선택의 여지가 없습니다. 이를 판별하는 가장 좋은 방법은 EXPLAIN명령문과 함께 명령문 을 사용하는 것 SELECT입니다. 데이터베이스가 데이터를 페치하기 위해 수행 할 추적 / 스캔 수는 EXPLAIN쿼리에서 리턴 한 "행"값의 곱입니다 . 이 경우 10 개의 테이블을 조인하는 쿼리가있었습니다. 특히 기록에 따르면, 추적은 DB를 블로그에 올렸고 DB 서버의 CPU 사용량을 300 % 이상으로 늘린 409M에 달했습니다. 쿼리를 훨씬 빠르게 분할하여 동일한 정보를 검색 할 수있었습니다.

간단히 말해서 복잡한 / 큰 쿼리를 분할하는 것이 합리적이지만 다른 경우에는 많은 성능 또는 유지 관리 문제가 발생할 수 있으며 이는 사례별로 처리해야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.