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


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.