JOIN 쿼리가 여러 쿼리보다 빠릅니까? 기본 쿼리를 실행 한 다음 기본 쿼리의 결과를 기반으로 다른 많은 SELECT를 실행합니다.
가입하면 응용 프로그램의 디자인이 많이 복잡해지기 때문에 묻습니다.
그들이 더 빠르면 누구나 대략적으로 대략적으로 얼마만큼을 근사 할 수 있습니까? 1.5x이면 상관하지 않지만 10x이면 내가 생각합니다.
JOIN 쿼리가 여러 쿼리보다 빠릅니까? 기본 쿼리를 실행 한 다음 기본 쿼리의 결과를 기반으로 다른 많은 SELECT를 실행합니다.
가입하면 응용 프로그램의 디자인이 많이 복잡해지기 때문에 묻습니다.
그들이 더 빠르면 누구나 대략적으로 대략적으로 얼마만큼을 근사 할 수 있습니까? 1.5x이면 상관하지 않지만 10x이면 내가 생각합니다.
답변:
특정 사례와 관련된 답변을 제공하기에는 너무 모호합니다. 그것은 많은 것들에 달려 있습니다. Jeff Atwood (이 사이트의 창립자)는 실제로 이것에 대해 썼습니다 . 대부분의 경우 올바른 인덱스가 있고 JOIN을 올바르게 수행하면 일반적으로 여러 번보다 1 회 트립하는 것이 더 빠릅니다.
내부 조인의 경우 일치하는 행만 가져 오기 때문에 단일 쿼리가 적합합니다. 왼쪽 조인의 경우 여러 쿼리가 훨씬 낫습니다 ... 다음 벤치 마크를 살펴보십시오.
5 개의 조인이있는 단일 쿼리
쿼리 : 8.074508 초
결과 크기 : 2268000
연속으로 5 개의 쿼리
결합 된 쿼리 시간 : 0.00262 초
결과 크기 : 165 (6 + 50 + 7 + 12 + 90)
.
두 경우 모두 동일한 결과를 얻습니다 (6 x 50 x 7 x 12 x 90 = 2268000).
왼쪽 조인은 중복 데이터와 함께 기하 급수적으로 더 많은 메모리를 사용합니다.
두 테이블의 조인 만 수행하는 것이 아니라 일반적으로 3 개 이상이고 다른 쿼리의 가치가있는 경우 메모리 제한은 나쁘지 않을 수 있습니다.
참고로 MySQL 서버는 내 응용 프로그램 서버 바로 옆에 있으므로 연결 시간을 무시할 수 있습니다. 연결 시간이 초 단위라면 이점이있을 수 있습니다.
솔직한
이 질문은 오래되었지만 일부 벤치 마크가 누락되었습니다. 나는 두 경쟁자에 대해 JOIN을 벤치마킹했습니다.
WHERE IN(...)
또는 동등한그 결과는 분명하다 : MySQL을, JOIN
이다 훨씬 더 빨리. N + 1 쿼리는 응용 프로그램의 성능을 크게 떨어 뜨릴 수 있습니다.
즉, 매우 적은 수의 별개의 외부 레코드를 가리키는 많은 레코드를 선택하지 않는 한. 극단적 인 경우에 대한 벤치 마크는 다음과 같습니다.
대다 관계를 조인하지 않으면 외래 키가 다른 테이블에 있고 주 테이블 데이터를 여러 번 복제하지 않는 한 일반적인 응용 프로그램에서 발생할 가능성이 거의 없습니다.
테이크 아웃 :
JOIN
자세한 내용은 Medium에 대한 내 기사 를 참조하십시오.
나는 실제로이 질문에 답을 찾고, 주어진 답변을 읽은 후에 DB 쿼리 성능을 비교하는 가장 좋은 방법은 고려할 변수가 많기 때문에 실제 숫자를 얻는 것에 만 동의 할 수 있습니다 그러나 나는 그들 사이의 숫자를 비교하면 거의 모든 경우에 좋지 않다고 생각합니다. 내 말은 숫자는 항상 허용되는 숫자와 비교해야하며 서로 확실히 비교해서는 안된다는 것입니다.
쿼리하는 한 가지 방법으로 0.02 초가 걸리고 다른 한 가지 방법으로 20 초가 걸리는 것을 이해하면 큰 차이가 있습니다. 그러나 한 쿼리 방법에 0.0000000002 초가 걸리고 다른 방법에 0.0000002 초가 걸리면 어떻게해야합니까? 두 경우 모두 하나의 방법은 무려 1000 배 빠른 다른 하나보다,하지만은 정말 두 번째 경우에 "무려"아직?
내가 개인적으로 본 결론 : 실적이 좋으면 쉬운 해결책을 찾으십시오.
50,000 행 테이블에서 하나의 행을 선택하고 100,000 행 테이블에서 하나의 행과 조인하는 빠른 테스트를 수행했습니다. 기본적으로 다음과 같습니다.
$id = mt_rand(1, 50000);
$row = $db->fetchOne("SELECT * FROM table1 WHERE id = " . $id);
$row = $db->fetchOne("SELECT * FROM table2 WHERE other_id = " . $row['other_id']);
vs
$id = mt_rand(1, 50000);
$db->fetchOne("SELECT table1.*, table2.*
FROM table1
LEFT JOIN table1.other_id = table2.other_id
WHERE table1.id = " . $id);
두 가지 선택 방법은 50,000 읽기에 3.7 초가 걸렸지 만 집에서 느린 컴퓨터에서는 JOIN이 2.0 초에 걸렸습니다. INNER JOIN과 LEFT JOIN은 차이가 없었습니다. 여러 행을 가져 오면 (예 : IN SET 사용) 비슷한 결과가 나타납니다.
실제 질문은 다음 과 같습니다. 이 레코드는 일대일 관계 또는 일대 다 관계 입니까?
TLDR 답변 :
일대일 인 경우, JOIN
명세서를 사용하십시오 .
일대 SELECT
다인 경우 서버 측 코드 최적화와 함께 하나 이상의 명령문을 사용하십시오.
최적화를 위해 SELECT를 사용하는 이유와 방법
SELECT
일대 다 관계를 기반으로하는 대규모 레코드 그룹에서 '조인 대신 여러 쿼리를 사용 JOIN
' 하면 '지수 적으로 메모리 누수 문제가 발생 하므로 최적의 효율성을 얻을 수 있습니다. 모든 데이터를 가져온 다음 서버 측 스크립팅 언어를 사용하여 정렬하십시오.
SELECT * FROM Address WHERE Personid IN(1,2,3);
결과 :
Address.id : 1 // First person and their address
Address.Personid : 1
Address.City : "Boston"
Address.id : 2 // First person's second address
Address.Personid : 1
Address.City : "New York"
Address.id : 3 // Second person's address
Address.Personid : 2
Address.City : "Barcelona"
여기서는 하나의 select 문에서 모든 레코드를 가져옵니다. 이것은 JOIN
다른 쿼리의 하위 구성 요소로 한 번에 하나씩 작은 그룹의 레코드를 가져 오는 것 보다 낫습니다 . 그런 다음 서버 측 코드로 구문 분석합니다 ...
<?php
foreach($addresses as $address) {
$persons[$address['Personid']]->Address[] = $address;
}
?>
최적화에 JOIN을 사용하지 않을 경우
JOIN
하나의 단일 레코드와 일대일 관계를 기반으로 한 큰 레코드 그룹을 작성하면 여러 SELECT
명령문에 비해 최적의 효율성을 얻을 수 있으며 이는 단순히 다음 레코드 유형을 가져옵니다.
그러나 JOIN
일대 다 관계로 레코드를 가져올 때 비효율적입니다.
예 : 데이터베이스 블로그에는 3 개의 관심 테이블 (블로그 포스트, 태그 및 주석)이 있습니다.
SELECT * from BlogPost
LEFT JOIN Tag ON Tag.BlogPostid = BlogPost.id
LEFT JOIN Comment ON Comment.BlogPostid = BlogPost.id;
블로그 게시물 1 개, 태그 2 개, 댓글 2 개가 있으면 다음과 같은 결과가 나타납니다.
Row1: tag1, comment1,
Row2: tag1, comment2,
Row3: tag2, comment1,
Row4: tag2, comment2,
각 레코드가 어떻게 복제되는지 확인하십시오. 좋아요, 2 개의 댓글과 2 개의 태그는 4 행입니다. 댓글 4 개와 태그 4 개가 있으면 어떻게 되나요? 당신은 8 개의 줄을 얻지 못합니다-당신은 16 개의 줄을 얻습니다 :
Row1: tag1, comment1,
Row2: tag1, comment2,
Row3: tag1, comment3,
Row4: tag1, comment4,
Row5: tag2, comment1,
Row6: tag2, comment2,
Row7: tag2, comment3,
Row8: tag2, comment4,
Row9: tag3, comment1,
Row10: tag3, comment2,
Row11: tag3, comment3,
Row12: tag3, comment4,
Row13: tag4, comment1,
Row14: tag4, comment2,
Row15: tag4, comment3,
Row16: tag4, comment4,
더 많은 테이블, 더 많은 레코드 등을 추가하면 문제는 대부분 중복 데이터로 가득 찬 수백 개의 행으로 빠르게 팽창합니다 .
이 중복 비용은 얼마입니까? 메모리 (SQL 서버 및 중복 제거를 시도하는 코드) 및 네트워킹 리소스 (SQL 서버와 코드 서버 간)
출처 : https://dev.mysql.com/doc/refman/8.0/en/nested-join-optimization.html ; https://dev.mysql.com/doc/workbench/en/wb-relationship-tools.html
별도의 쿼리와 조인을 모두 구성한 다음 각각의 시간을 정하십시오. 실제 숫자보다 큰 도움은 없습니다.
더 나은 방법은 각 쿼리의 시작 부분에 "EXPLAIN"을 추가하는 것입니다. 이것은 MySQL이 데이터 요청에 응답하기 위해 사용하는 서브 쿼리 수와 각 쿼리에 대해 스캔 된 행 수를 알려줍니다.
내 경험상, 특히 큰 데이터 세트를 검색 할 때 여러 쿼리를 실행하는 것이 일반적으로 더 빠릅니다.
PHP와 같은 다른 응용 프로그램에서 데이터베이스와 상호 작용할 때 한 서버를 여러 번 방문해야한다는 주장이 있습니다.
서버로의 트립 수를 제한하고 종종 더 빠를뿐만 아니라 응용 프로그램을보다 쉽게 읽을 수있는 여러 쿼리를 실행하는 다른 방법이 있습니다 (예 : mysqli_multi_query).
나는 SQL에 관해서 초보자가 아니며, 개발자, 특히 주니어는 똑똑해 보이기 때문에 매우 영리한 조인을 작성하는 데 많은 시간을 소비하는 경향이 있다고 생각하지만 실제로는 데이터를 추출하는 현명한 방법이 있습니다 단순한.
마지막 단락은 개인적인 의견이지만 이것이 도움이되기를 바랍니다. 누가 벤치마킹해야한다고 말하지만 다른 사람들과 동의합니다. 두 가지 방법 모두 은총 알이 아닙니다.
조인을 사용해야하는지 여부는 무엇보다 조인 이 의미 가 있는지에 대한 것 입니다. 거의 모든 경우에 성능이 크게 저하 되므로 그 시점에서만 성능을 고려해야 합니다.
성능 차이는 주로 쿼리하는 정보가 얼마나 관련성이 있는지에 달려 있습니다. 조인은 작동 하며 데이터가 관련되어 있고 올바르게 색인을 생성 할 때 빠르지 만 종종 중복성과 결과가 필요한 것보다 더 많습니다. 그리고 데이터 세트가 직접 관련되어 있지 않은 경우 단일 쿼리에서 데이터 세트를 고수하면 Cartesian 제품 (기본적으로 가능한 모든 행 조합)이 만들어 지므로 원하는 것은 아닙니다.
이것은 종종 일대 다 관계에 의해 발생합니다. 예를 들어 HoldOffHunger의 답변 은 게시물, 태그 및 주석에 대한 단일 쿼리를 언급했습니다. 댓글은 태그와 마찬가지로 게시물과 관련이 있지만 태그는 댓글과 관련이 없습니다.
+------------+ +---------+ +---------+
| comment | | post | | tag |
|------------|* 1|---------|1 *|---------|
| post_id |-----| post_id |-----| post_id |
| comment_id | | ... | | tag_id |
| user_id | | | | ... |
| ... | | | | ... |
+------------+ +---------+ +---------+
이 경우에는 적어도 두 개의 별도 쿼리 인 것이 분명합니다. 태그와 주석을 결합하려고하면 둘 사이에 직접적인 관계가 없기 때문에 가능한 모든 태그와 주석 조합으로 끝납니다. many * many == manymany
. 그 외에도 게시물과 태그는 관련이 없으므로 두 쿼리를 병렬로 수행하여 잠재적 인 이익을 얻을 수 있습니다.
그러나 다른 시나리오를 고려해 봅시다. 게시물에 댓글을 달고 댓글 작성자의 연락처 정보를 원합니다.
+----------+ +------------+ +---------+
| user | | comment | | post |
|----------|1 *|------------|* 1|---------|
| user_id |-----| post_id |-----| post_id |
| username | | user_id | | ... |
| ... | | ... | +---------+
+----------+ +------------+
여기에서 조인을 고려해야합니다. 훨씬 더 자연스러운 쿼리 일뿐만 아니라 대부분의 데이터베이스 시스템 (MySQL 포함)에는 많은 똑똑한 사람들이 쿼리 최적화에 많은 노력을 기울이고 있습니다. 별도의 쿼리의 경우 각 쿼리는 이전 쿼리의 결과에 따라 달라 지므로 쿼리를 병렬로 수행 할 수 없으며 총 시간은 쿼리의 실제 실행 시간뿐만 아니라 결과를 가져 오는 데 소요 된 시간이됩니다. 다음 쿼리의 ID를 통해 행을 연결하는 등
다음은 100 개의 유용한 쿼리가있는 링크입니다. 이들은 Oracle 데이터베이스에서 테스트되었지만 SQL이 표준이라는 것을 기억하십시오. Oracle, MS SQL Server, MySQL과 다른 데이터베이스의 차이점은 SQL 언어입니다.
이진 답변이 없다는 것을 의미하는 몇 가지 요소가 있습니다. 성능에 가장 적합한 것은 환경에 따라 다릅니다. 그런데 식별자가있는 단일 선택이 1 초 미만이 아닌 경우 구성에 문제가있을 수 있습니다.
실제 질문은 어떻게 데이터에 액세스하길 원하는지입니다. 단일 선택은 후기 바인딩을 지원합니다. 예를 들어 직원 정보 만 원하는 경우 직원 테이블에서 선택할 수 있습니다. 외래 키 관계를 사용하여 나중에 필요한 경우 관련 리소스를 검색 할 수 있습니다. 선택은 이미 지적해야 할 열쇠가 있으므로 매우 빠르며 필요한 항목 만 검색하면됩니다. 네트워크 대기 시간은 항상 고려해야합니다.
조인은 모든 데이터를 한 번에 검색합니다. 보고서를 생성하거나 그리드를 채우는 경우 정확히 원하는 것일 수 있습니다. 이 시나리오에서는 컴파일 및 옵토마 이즈 된 조인이 단일 선택보다 빠를 것입니다. Ad-hoc 조인은 빠르지 않을 수 있으므로이를 저장 프로 시저로 컴파일해야합니다. 속도 응답은 DBMS가 데이터를 검색하기 위해 수행하는 단계를 정확히 설명하는 실행 계획에 따라 다릅니다.