빠른 쿼리를 위해 열이 중복됩니까?


30

제목이 너무 의미가 없지만이 문제에 대한 더 나은 제목을 생각할 수 없었습니다.

나는 다음과 같은 테이블이 있습니다

프로젝트

  • 신분증
  • 이름

고객

  • 신분증
  • id_project
  • 이름

지불

  • 신분증
  • id_customer
  • 날짜
  • 합집합

사용자가 시스템에 들어가면 특정 프로젝트에 액세스 할 수 있습니다. 이제 해당 프로젝트에 대한 모든 지불금을 나열하고 싶습니다.

SELECT FROM payments where id_customer in (SELECT id from customers where id_project = 5)

내 질문은 : 지불 테이블에 id_project 열을 추가하는 것이 좋지 않으면 쿼리가 더 쉽고 빠릅니다.


1
따라서 쿼리는 최신 RDBMS에서 문제가되지 않습니다 (또는 더 나은 경우에는 join을 사용하십시오).
garik

4
동의, subselect 대 조인에 대한 쿼리 계획을 얻고 어느 것이 더
좋은지

1
@igor가 JOIN 또는 IN 사용에 대해 언급 했으므로이 SO 게시물을 살펴볼 가치가 있다고 생각합니다.
CoderHawk

답변:


52

비정규 화가 의미가 있는지 묻는 것 같습니다 .

비정규 화는 중복 데이터를 추가하거나 데이터를 그룹화하여 데이터베이스의 읽기 성능을 최적화하는 프로세스입니다. 경우에 따라 비정규 화는 관계형 데이터베이스 소프트웨어에 내재 된 비 효율성을 커버하는 데 도움이됩니다. 관계형 정규화 된 데이터베이스는 고성능으로 조정되어 있어도 물리적 데이터 스토리지에 대한 액세스 부하가 심합니다.

대답은 항상 "의존적"이므로 여기에 내 경험 법칙이 있습니다.

만약 ...

  • 데이터의 양이 크지 않다
  • 이미 많은 조인을하지 않고 있습니다
  • 데이터베이스 성능이 현재 병목 현상이 아닙니다

그런 다음 정규화 상태유지하십시오 . 예, 비정규 화 속도는 더 빠르지 만 시스템에 중복 데이터 (유지 및 동기화 상태를 유지해야하는 데이터)가 있음을 의미합니다. 해당 데이터에 대해 더 이상 "하나의 소스"가 없지만 벗어날 수있는 여러 소스가 있습니다. 이는 시간이 지남에 따라 위험하므로 일부 벤치마킹을 바탕으로해야 할 이유가없는 한 그렇게하지 않아야합니다.

나는 언제 비정규 화 할 것입니다 ...

  • 데이터의 양이 매우 크다
  • 조인은 비싸고 사소한 쿼리조차 반환하려면 많은 작업을 수행해야합니다.
  • 데이터베이스 성능에 병목 현상이 발생하거나 최대한 빨리 가고 싶습니다

현대 하드웨어에서는 조인이 매우 빠르지 만 결코 무료 가 아닙니다 .


9

다음과 같이 쿼리를 다시 작성하는 것이 좋습니다.

SELECT payments.*
FROM   customers
JOIN   payments 
ON     payments.id_customer = customers.id
WHERE  customers.id_project = 5

이것은 간결하지 않은 것으로 보이며 좋은 쿼리 플래너는 위의 조인으로 상관 된 하위 쿼리를 수행하려고 시도하고 실행하려고 시도하지만 잘못된 쿼리 플래너는 인덱스 스캔을 수행 payments.id_customer할 수 있습니다 (관련 인덱스가 있다고 가정) 보다 효율적인 방법으로 작업하는 대신) (또는 더 나쁜 테이블 스캔)을 수행하십시오. 이 쿼리의 배열이 더 복잡한 것으로 랩핑되어 있으면 좋은 쿼리 플래너조차도 최적화를 보지 못할 수 있습니다. 하위 쿼리가 아닌 조인으로 관계를 표현하면 데이터 구조를 변경하는 것보다 더 큰 차이를 만들 수 있습니다.

Jeff가 말했듯이 모든 비정규 화는 신중하게 고려해야합니다. 특히 일부보고 목적으로 성능을 쉽게 향상시킬 수 있지만 지원하는 비즈니스 로직의 버그로 인해 불일치가 발생할 수 있습니다.

참고로 : 분명히 나는 ​​당신의 사업을 모른다. 그래서 나는 뭔가를 놓칠 수 있지만 테이블 관계는 나에게 이상한 것처럼 보인다. 그들은 당신이 적어도 오랜 기간 동안 내 경험상 사실이 아닌 동일한 고객을 가진 하나 이상의 프로젝트를 가질 수 없음을 의미합니다.

customer     project      payment
--------     --------     -------
                          pa_id
             pr_id    <-- payment
cu_id    <-- customer     

또는 덜 표준화 된 경우 (필요한지 의심 스럽지만) :

customer     project      payment
--------     --------     --------
                          pa_id
             pr_id    <-- payment
cu_id    <-- customer 
           `------------- customer    

물론 두 고객과의 공동 프로젝트 가능성을 여전히 할인합니다 ...


3
성능의 첫 번째 규칙 : 프로덕션에서 *를 사용하지 마십시오!
Brian Ballsun-Stanton

@ 브라이언 : 매우 유효한 포인트. 또한 select 절에서 *를 피할 수있는 잠재적 인 성능 영향뿐만 아니라 sys.depends가 DROP VIEW+ CREATE VIEW대신 사용 되어 kilter에서 벗어날 경우 MSSQL에서 view-on-view의 열 순서 문제를 피할 수 있습니다 ALTER VIEW.
David Spillett

@Brian 나는 쓰기 쉽게 *를 넣었다.
가브리엘 솔로몬

이 프로젝트는 도메인에있는 독립적 인 응용 프로그램으로 생각되며 다른 고객에 속하므로 고객은 다른 프로젝트에서 동일한 계정을 가질 수 없습니다
Gabriel Solomon

4

일부 데이터베이스에서는 복잡한 쿼리를 기반으로 많은 양의 데이터를 사용하여 복잡한 VIEWS 대신 "Materialized Views"를 생성 할 수 있습니다.이 방법을 사용하면 기록이 증가한 응용 프로그램 시스템에서 비정규 화를 피할 수 있습니다. 구체화 된 뷰 "에서는 구체화 된 뷰에서 사용될 새로 고침 방법 및 스토리지 양에 대한 명확한 아이디어가 있어야합니다.

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