2009-03-04 2 views
4

나는 간단한 정규화 된 데이터베이스로 웹 사이트에서 일하고있다.합계를 비정규 화해야합니까?

페이지라는 테이블과보기라는 테이블이 있습니다. 페이지를 볼 때마다 해당보기의 고유 레코드가보기 테이블에 기록됩니다.

사이트에 페이지를 표시 할 때 간단한 MySQL COUNT()를 사용하여 표시 할 뷰의 수를 합산합니다.

데이터베이스 디자인은이 문제를 제외하고는 괜찮습니다. 수천 중에서 가장 많이 본 상위 10 개 페이지를 검색하는 방법에 대한 손실이 있습니다.

각 페이지의 총보기 수를 유지하기 위해 Pages.views 열을 추가하여 페이지 테이블을 비정규 화해야합니까? 아니면 가장 많이 조회되는 상위 10 개 페이지를 쿼리하는 효율적인 방법이 있습니까?

답변

8
SELECT p.pageid, count(*) as viewcount FROM 
    pages p 
    inner join views v on p.pageid = v.pageid 
    group by p.pageid 
    order by count(*) desc 
    LIMIT 10 OFFSET 0; 

필자는 테스트 할 수 없지만이 줄을 따라 테스트 할 수 있습니다. 퍼포먼스 제약 조건 (나는 "조숙 한 최적화"라는 용어를 배웠고, 그렇게한다면 적용하는 것 같다) 때문에 값을 저장하지 않을 것이다.

+1

+1 성능 문제가 발생할 때까지 총계를 저장하지 않음에 대한 설명입니다. – Thilo

1

아마도 페이지 테이블에보기 열을 포함하게됩니다.

정상적으로 나를 합리적인 타격처럼 보입니다. 특히 내가보기를 삭제하는 것을 상상할 수 없기 때문에 카운트가 헛되이 나오지 않을 것이라고 기대할 수는 없습니다. 참조 무결성은이 경우 매우 중요하지 않습니다.

1

데이터베이스 정규화는 모두 데이터를 저장하는 가장 효율적인 방법입니다. 이는 트랜잭션 처리에 적합하지만 종종 효율적으로 데이터를 다시 가져올 필요성과 직접적으로 충돌합니다. 일반적으로이 문제는보다 쉽게 ​​액세스 할 수있는 사전 처리 된 데이터로 테이블 (인덱스, 구체화 된보기, 롤업 테이블 ...)을 파생시킴으로써 해결됩니다. 여기 (약간 날짜가있는) 전문 용어는 데이터웨어 하우징입니다.

페이지 테이블을 정규화 된 상태로 유지하려고하지만 합계가있는 추가 테이블이 필요하다고 생각합니다. 최근에 계산 한 횟수에 따라 원본 테이블을 업데이트 할 때 테이블을 업데이트하거나 정기적으로 합계를 다시 계산하는 백그라운드 작업을 수행 할 수 있습니다.

매우 많은 수의 레코드 또는 매우 많은 수의 동시 액세스가있는 경우가 아니면 성능상의 문제가있는 경우에만이 작업을 수행하려고합니다. 테이블을 소유하고 있지 않은 상태로 전환 할 수 있으려면 코드를 유연하게 유지하십시오.

0

이 경우 비정규 화가 올바르게 작동합니다. 귀하의 손실은 여분의 열에 의해 사용 된 여분의 저장실입니다.

또는 트래픽이 낮을 때마다 야간에이 정보를 채우도록 예약 된 작업을 설정할 수 있습니다.

이 쿼리를 수동으로 실행하지 않는 한이 경우 페이지 수를 즉시 알 수있는 기능이 손실됩니다.

비정규 화를 통해 성능을 향상시킬 수 있습니다.

- 크리스

+0

손실은 추가 열과 일관성 유지의 필요성입니다. 나는 그것이 비록이 경우에 정당화된다고 동의한다. – thomasrutter

3

유지 관리하려는 정보의 레벨에 따라 다릅니다. 언제 보았는지 기록하고 싶습니까? 그럼 별도의 테이블이 좋습니다. 그렇지 않으면보기에 대한 열이 이동하는 방법입니다.또한 별도의 열을 유지하면 각 페이지 뷰가 해당 행에 대한 열을 업데이트하려고하기 때문에 테이블이 더 자주 잠기 게됩니다.

Select pageid, Count(*) as countCol from Views 
group by pageid order by countCol DESC 
LIMIT 10 OFFSET 0; 
관련 문제