[sql] 확장 성을 고려할 때 조인이 나쁜 이유는 무엇입니까?

조인이 나쁘거나 ‘느린’이유는 무엇입니까? 나는 이것을 한 번 더 들었다는 것을 안다. 이 인용구를 찾았습니다

문제는 조인이 상대적으로 느리고 특히 매우 큰 데이터 세트에서 느리고 웹 사이트가 느리다는 것입니다. 디스크에서 분리 된 모든 정보를 가져 와서 모두 다시 모으려면 오랜 시간이 걸립니다.

출처

나는 항상 그들이 특히 PK를 찾을 때 빠르다고 생각했습니다. 왜 ‘느리다’고?



답변

확장 성은 작업 단위당 리소스 사용을 최소화하기 위해 반복되는 작업을 사전 컴퓨팅, 분산 또는 기본 요소로 축소하는 것입니다. 확장을 잘하기 위해 필요하지 않은 작업을 수행하지 않고 실제로 수행하는 작업을 최대한 효율적으로 수행합니다.

물론 두 개의 개별 데이터 소스를 결합하는 것은 사용자가 요청하는 지점에서 라이브로 수행해야하는 작업이기 때문에 적어도 결합하지 않는 것에 비해 상대적으로 느립니다.

그러나 대안은 더 이상 두 개의 개별 데이터를 전혀 가지지 않는다는 것을 기억하십시오. 두 개의 서로 다른 데이터 포인트를 동일한 레코드에 넣어야합니다. 어딘가에 결과없이 두 개의 서로 다른 데이터를 결합 할 수 없으므로 장단점을 이해해야합니다.

좋은 소식은 현대의 관계형 데이터베이스가 조인에 능하다 는 입니다. 좋은 데이터베이스를 잘 사용하면 조인이 느리다고 생각해서는 안됩니다. 원시 조인을 가져와 훨씬 더 빠르게 만드는 확장 성 친화적 인 방법은 여러 가지가 있습니다 .

  • 자연 키가 아닌 대리 키 (자동 번호 / ID 열)에서 조인합니다. 이는 조인 작업 중에 더 작은 (따라서 더 빠른) 비교를 의미합니다.
  • 인덱스
  • 구체화 된 / 인덱싱 된 뷰 (사전 계산 된 조인 또는 관리 된 비정규 화로 생각)
  • 계산 된 열. 이를 사용하여 조인의 키 열을 해시하거나 미리 계산할 수 있으므로 조인에 대한 복잡한 비교가 훨씬 더 작아지고 잠재적으로 사전 인덱싱 될 수 있습니다.
  • 테이블 파티션 (로드를 여러 디스크로 분산하거나 테이블 스캔 일 수있는 것을 파티션 스캔으로 제한하여 대용량 데이터 세트에 도움이 됨)
  • OLAP (특정 종류의 쿼리 / 조인 결과를 미리 계산합니다. 사실은 아니지만 일반적인 비정규 화 라고 생각할 수 있습니다. )
  • 복제, 가용성 그룹, 로그 전달 또는 기타 메커니즘을 통해 여러 서버가 동일한 데이터베이스에 대한 읽기 쿼리에 응답 할 수 있으므로 여러 서버간에 워크로드를 확장 할 수 있습니다.
  • 복잡한 조인이 필요한 쿼리를 다시 실행하지 않도록 Redis와 같은 캐싱 레이어를 사용합니다.

나는 지금까지 말을 갈 것 관계형 데이터베이스 모두에 존재하는 주된 이유는 당신이 할 수 있도록하는 것입니다 효율적으로 결합 * . 확실히 구조화 된 데이터를 저장하는 것만이 아닙니다 (csv 또는 xml과 같은 플랫 파일 구조를 사용하여 수행 할 수 있음). 내가 나열한 몇 가지 옵션을 사용하면 사전에 조인을 완전히 구축 할 수 있으므로 쿼리를 실행하기 전에 결과가 이미 완료되었습니다. 마치 데이터를 비정규 화 한 것처럼 (당연히 쓰기 작업 속도가 느려집니다).

조인이 느린 경우 데이터베이스를 올바르게 사용하고 있지 않을 수 있습니다.

비정규 화는 이러한 다른 기술이 실패한 후에 만 ​​수행되어야합니다. “실패”를 진정으로 판단 할 수있는 유일한 방법은 의미있는 성능 목표를 설정하고 해당 목표에 대해 측정하는 것입니다. 측정하지 않았다면 비정규 화에 대해 생각조차하기에는 너무 이르다.

* 즉, 단순한 테이블 모음과는 다른 엔티티로 존재합니다. 실제 rdbms의 또 다른 이유는 안전한 동시 액세스입니다.


답변

조인은 비정규 화를 통해 피하는 것보다 느릴 수 있지만 올바르게 사용하면 (적절한 인덱스가있는 열에 조인하는 등) 본질적으로 느리지 않습니다 .

비정규 화는 잘 설계된 데이터베이스 스키마가 성능 문제를 나타내는 경우 고려할 수있는 많은 최적화 기술 중 하나입니다.


답변

기사에 따르면 조인이없는 경우에 비해 느립니다. 이것은 비정규 화로 달성 할 수 있습니다. 그래서 속도와 정규화 사이에는 상충 관계가 있습니다. 조기 최적화도 잊지 마세요 🙂


답변

우선, 관계형 데이터베이스의 존재 이유 (존재 이유)는 엔티티 간의 관계를 모델링 할 수 있다는 것입니다. 조인은 단순히 이러한 관계를 탐색하는 메커니즘입니다. 확실히 명목상의 비용이 들지만 조인이 없으면 관계형 데이터베이스를 가질 이유가 없습니다.

학문적 세계에서 우리는 다양한 정규형 (1st, 2nd, 3rd, Boyce-Codd 등)과 같은 것을 배우고 다양한 유형의 키 (기본, 외국, 대체, 고유 등) 및 방법을 배웁니다. 이러한 것들은 데이터베이스를 설계하는 데 적합합니다. 그리고 SQL의 기초를 배우고 구조와 데이터 (DDL 및 DML)를 조작합니다.

기업 세계에서 많은 학문적 구성은 우리가 믿었던 것보다 훨씬 덜 실행 가능하다는 것이 밝혀졌습니다. 완벽한 예는 기본 키의 개념입니다. 학문적으로는 테이블에서 한 행을 고유하게 식별하는 속성 (또는 속성 모음)입니다. 따라서 많은 문제 영역에서 적절한 학문적 기본 키는 3 개 또는 4 개의 속성의 조합입니다. 그러나 현대 기업 세계의 거의 모든 사람들은 자동 생성 된 순차적 정수를 테이블의 기본 키로 사용합니다. 왜? 두 가지 이유. 첫 번째는 FK를 사방으로 마이그레이션 할 때 모델을 훨씬 더 깔끔하게 만들기 때문입니다. 두 번째이며이 질문과 가장 밀접한 관계는 조인을 통해 데이터를 검색하는 것이 4 개의 varchar 열 (몇몇 사람들이 이미 언급했듯이)보다 단일 정수에서 더 빠르고 효율적이라는 것입니다.

이제 실제 데이터베이스의 두 가지 특정 하위 유형에 대해 좀 더 자세히 살펴 보겠습니다. 첫 번째 유형은 트랜잭션 데이터베이스입니다. 이는 최신 사이트를 구동하는 많은 전자 상거래 또는 콘텐츠 관리 응용 프로그램의 기반입니다. 트랜잭션 DB를 사용하면 “트랜잭션 처리량”에 대해 크게 최적화하고 있습니다. 대부분의 상거래 또는 콘텐츠 앱은 쿼리 성능 (특정 테이블의)과 삽입 성능 (다른 테이블의) 간의 균형을 맞춰야하지만, 각 앱에는 고유 한 비즈니스 중심 문제가 해결되어야합니다.

두 번째 유형의 실제 데이터베이스는보고 데이터베이스입니다. 이들은 거의 독점적으로 비즈니스 데이터를 집계하고 의미있는 비즈니스 보고서를 생성하는 데 사용됩니다. 일반적으로 데이터가 생성되는 트랜잭션 데이터베이스와 모양이 다르며 대량 데이터 세트 또는 복잡한 데이터 세트의 쿼리 성능과 대량 데이터로드 (ETL) 속도에 대해 고도로 최적화되어 있습니다.

각각의 경우 개발자 또는 DBA는 기능과 성능 곡선의 균형을 신중하게 조정해야하며, 방정식 양쪽에 많은 성능 향상 트릭이 있습니다. Oracle에서는 “계획 설명”을 수행 할 수 있으므로 쿼리가 구문 분석되고 실행되는 방식을 구체적으로 볼 수 있습니다. DB의 적절한 인덱스 사용을 극대화하려고합니다. 하나의 정말 불쾌한 금지는 쿼리의 where 절에 함수를 넣는 것입니다. 그렇게 할 때마다 Oracle이 해당 특정 열에 대한 인덱스를 사용하지 않도록 보장하고 Explain 플랜에서 전체 또는 부분 테이블 스캔을 볼 수 있습니다. 이것은 쿼리가 어떻게 작성 될 수 있는지에 대한 하나의 구체적인 예일 뿐이며 결과적으로 속도가 느려지고 조인과 관련이 없습니다.

테이블 스캔에 대해 이야기하는 동안 테이블 크기에 비례하여 쿼리 속도에 분명히 영향을 미칩니다. 100 개 행의 전체 테이블 스캔은 눈에 띄지 않습니다. 1 억 개의 행이있는 테이블에서 동일한 쿼리를 실행하면 다음 주에 반환해야합니다.

정규화에 대해 잠시 이야기 해 봅시다. 이것은 과도한 스트레스를받을 수있는 매우 긍정적 인 학문적 주제입니다. 정규화에 대해 이야기 할 때 대부분의 경우 중복 데이터를 자체 테이블에 넣고 FK를 마이그레이션하여 제거하는 것을 의미합니다. 사람들은 일반적으로 2NF와 3NF가 설명하는 전체 의존성 문제를 건너 뜁니다. 그러나 극단적 인 경우에는 정규화 되었기 때문에 코드를 작성할 수있는 거대하고 완전한 짐승 인 완벽한 BCNF 데이터베이스를 보유 할 수 있습니다.

그래서 우리는 어디에서 균형을 잡을까요? 하나의 베스트 답변은 없습니다. 모든 더 나은 대답은 구조 유지 관리의 용이성, 데이터 유지 관리의 용이성 및 코드 생성 / 유지 관리의 용이성 사이의 타협 인 경향이 있습니다. 일반적으로 데이터 중복이 적을수록 좋습니다.

그렇다면 조인이 때때로 느린 이유는 무엇입니까? 때로는 잘못된 관계형 디자인입니다. 때로는 비효율적 인 인덱싱입니다. 때로는 데이터 볼륨 문제입니다. 때로는 끔찍하게 작성된 쿼리입니다.

그렇게 긴 답변을 드려서 미안하지만, 4 개의 글 머리 기호로 답하는 것보다 내 댓글에 대해 더 자세한 맥락을 제공해야한다는 느낌이 들었습니다.


답변

테라 바이트 크기의 데이터베이스를 사용하는 사람들은 여전히 ​​조인을 사용합니다. 성능 측면에서 작업 할 수 있다면 조인을 사용할 수 있습니다.

denomalize하지 않는 데는 여러 가지 이유가 있습니다. 첫째, 선택 쿼리의 속도는 데이터베이스의 유일한 또는 주요 관심사가 아닙니다. 데이터의 무결성이 첫 번째 관심사입니다. 비정규 화하는 경우 상위 데이터가 변경 될 때 데이터를 비정규 화 상태로 유지하는 기술을 적용해야합니다. 따라서 client_Id의 클라이언트 테이블에 조인하는 대신 모든 테이블에 클라이언트 이름을 저장한다고 가정합니다. 이제 클라이언트 이름이 변경되면 (시간이 지남에 따라 일부 클라이언트 이름이 변경 될 확률이 100 %) 이제 해당 변경 사항을 반영하도록 모든 하위 레코드를 업데이트해야합니다. 이 작업을 수행하면 계단식 업데이트가 수행되고 백만 개의 하위 레코드가있는 경우 얼마나 빠르며 잠금 문제가 발생하고 작업이 지연되는 동안 얼마나 많은 사용자가 작업 지연을 겪을 것이라고 생각하십니까? 비정규 화하는 대부분의 사람들은 “

비정규 화는 올바르게 수행하려면 데이터베이스 성능 및 무결성에 대한 철저한 이해가 필요한 복잡한 프로세스입니다. 직원에 대한 전문 지식이없는 한 비정규 화를 시도하지 마십시오.

조인은 몇 가지 작업을 수행하면 충분히 빠릅니다. 먼저 suggorgate 키를 사용하면 int 조인이 거의 가장 빠른 조인입니다. 두 번째는 항상 외래 키를 인덱싱합니다. 파생 테이블 또는 조인 조건을 사용하여 필터링 할 더 작은 데이터 집합을 만듭니다. 매우 복잡한 대규모 데이터베이스가있는 경우 대규모 데이터베이스 분할 및 관리 경험이있는 전문 데이터베이스 담당자를 고용하십시오. 조인을 제거하지 않고 성능을 향상시킬 수있는 많은 기술이 있습니다.

쿼리 기능 만 필요하면 비정규 화 될 수 있고 사용자 데이터 입력이 아닌 ETL 도구 (속도 최적화)를 통해 채워지는 데이터웨어 하우스를 설계 할 수 있습니다.


답변

조인이 느린 경우

  • 데이터가 잘못 인덱싱되었습니다.
  • 제대로 필터링되지 않은 결과
  • 잘못 작성된 쿼리 결합
  • 매우 크고 복잡한 데이터 세트

따라서 데이터 세트가 클수록 쿼리에 더 많은 처리가 필요하지만 위의 처음 세 가지 옵션을 확인하고 작업하면 종종 훌륭한 결과를 얻을 수 있습니다.

소스는 옵션으로 비정규 화를 제공합니다. 더 나은 대안을 다 사용한 경우에만 괜찮습니다.


답변

각 측면에서 많은 레코드 부분을 스캔해야하는 경우 조인 속도가 느려질 수 있습니다.

이렇게 :

SELECT  SUM(transaction)
FROM    customers
JOIN    accounts
ON      account_customer = customer_id

인덱스가에 정의되어 있어도 account_customer후자의 모든 레코드를 스캔해야합니다.

쿼리 목록의 경우 괜찮은 최적화 프로그램은 인덱스 액세스 경로를 고려하지 않고 대신 a HASH JOIN또는 a MERGE JOIN를 수행합니다 .

다음과 같은 쿼리의 경우 :

SELECT  SUM(transaction)
FROM    customers
JOIN    accounts
ON      account_customer = customer_id
WHERE   customer_last_name = 'Stellphlug'

조인은 가장 빠를 것입니다. 먼저 customer_last_name모든 Stellphlug (물론 많지는 않지만)를 필터링하는 데 인덱스 가 사용 된 다음 account_customer각 Stellphlug 에 대한 인덱스 스캔 이 실행되어 트랜잭션을 찾습니다.

accounts및 에서 수십억 개의 레코드가 될 수 있다는 사실에도 불구하고 실제로 customers스캔해야하는 레코드는 거의 없습니다.