저장 및 집계 값 계산


96

집계 값을 저장할시기와 계산할시기를 결정하기위한 지침 또는 경험 법이 있습니까?

예를 들어, 사용자가 평가할 수있는 위젯이 있다고 가정합니다 (아래 스키마 참조). 위젯을 표시 할 때마다 Ratings테이블 에서 평균 사용자 등급을 계산할 수 있습니다. 또는 평균 등급을 Widget테이블 에 저장할 수 있습니다 . 이렇게하면 위젯을 표시 할 때마다 등급을 계산하지 않아도되지만 사용자가 위젯을 평가할 때마다 평균 등급을 다시 계산해야합니다.

Ratings       Widgets
---------     -------
widget_id     widget_id
user_id       name              
rating        avg_rating  <--- The column in question

답변:


58

따라 다릅니다. 미리 계산 된 집계 값은 쓰기에 더 큰 부하를 가하여이를 도출하기가 어렵습니다.

파생 값에 자주 액세스하는 경우 사전 계산은 유효한 비정규 화 단계입니다. 그러나이 경우 구체화 된 뷰 (디스크에 작성되고 트리거에 의해 상위 테이블에 링크 된 뷰)를 사용하는 것이 좋습니다. 구체화 된 뷰는 자주 요청되지만 지루하고 파생적인 데이터를 저장하도록 설계되었으며 많은 수의 쓰기와 적은 수의 읽기에 유용합니다.

높은 쓰기, 높은 읽기 시나리오에서는 구체화 된보기의 효과를 모방하지만 실시간보다는 적은 백그라운드에서 작업을 수행하는 것을 고려하십시오. 이는 쓰기 및 읽기 성능을 유지하면서 "충분히 좋은"평균을 제공합니다.

어떤 상황에서도 파생 된 열을 "정상"열처럼 취급하지 않아야합니다. 위젯 "보기"에 표시된 데이터가 테이블의 다른 곳에 존재하는지 확인하여 배치 한 프로세스에 따라 전체 튜플을 파생시킬 수 있습니다. 이 질문은 또한 데이터베이스 (및 데이터베이스 버전)에 따라 다르므로 일반 크기의 데이터 세트 및 구체화 된 뷰에 대해 적절한 인덱스를 사용하여 집계의 성능 테스트를 권장합니다.


나는 이 논의가 구체화 된 견해에 매우 도움이 된다는 것을 알았습니다 . Oracle에 맞게 조정되었지만 일반적으로 이해할 수 있습니다. MySQL 배경에서 온 나와 같은 사람들에게는 MySQL보기가 구체화보기와 다르며 가상이며 디스크에 저장하지 않습니다 (내가 준 링크에서 이야기했듯이).
Siddhartha

공감! 정확한 질문을하려고했습니다 .SMA, EMA, WMA, RSI 등과 같은 지표를 저장해야하며 무거운 계산이 필요합니다. 현재 수동으로 새로 고치는 테이블을 만들고 있었고이 지표는 매번 100 % 변경됩니다. 새로운 데이터가 들어오고이를 유지하기위한 좋은 전략은 무엇입니까? 모두가 뷰를 좌우로 쿼리하기 시작하면 뷰가 데이터베이스를 완전히 찢어 버릴 것입니다.
PirateApp

11

기본 숫자가 얼마나 자주 변경 / 업데이트되는지에 따라 값을 계산 / 표시해야하는 빈도.

따라서 1 시간에 한 번만 변경되는 값을 표시하는 일일 조회수가 10k 인 웹 사이트가있는 경우 기본 값이 변경 될 때 (데이터베이스 트리거 일 수 있음) 계산합니다.

통계가 두 번째로 변경되는 통계를 볼 수 있지만 세 사람 만 액세스 할 수 있고 하루에 두 번만 볼 수있는 도구가 있다면 계산할 가능성이 더 큽니다. 즉석에서. (처음에 오래된 데이터가있는 것이 큰 문제가 아니라고 계산하는 데 몇 분이 걸리지 않는 한 ... 내 상사는 매 시간마다 cron에서 물건을 생성하도록 지시하므로 그는 가지고 있지 않습니다. 그가보고 싶을 때까지 기다리십시오.)


15 분마다, 메트릭 당 1000 개의 행으로 100 % 변경되는 10 개의 메트릭
PirateApp

1
@PirateApp 및 평균 15 분 창에 몇 번 표시됩니까? 당신이 할 수있는 일은 15 분 창에 첫 번째 요청으로 생성 한 다음 계속해서 다시로드를 계속하는 사람들을 위해 캐시합니다.
Joe

그렇게 내가이어야 가정 만명이 선발을 위해 그것을 볼 수있을 것입니다 웹 사이트에 올라있을 것입니다, 사이트는 사용자의 행동에 실제 데이터가 그렇게 해달라고 살고 밤은
PirateApp

1
문제는 얼마나 자주 요청이 변경되는지에 대한 요청입니다. 따라서 기본 데이터가 변경되기 전에 10,000 번 표시 될 항목을 미리 생성 한 경우에는 미리 생성하십시오. 데이터가 한 번만 보이거나 한 번 미만인 경우 (데이터가 너무 빠르게 변경되거나 페이지가 거의 보이지 않기 때문에) 그렇지 않습니다.
Joe

4

StaleWidgets 테이블을 "유효하지 않은"(재 계산 될) 위젯 큐로 사용하십시오. 이러한 값을 다시 계산할 수있는 다른 스레드 (비동기식) 작업을 사용하십시오. 재 계산 기간 또는 순간은 시스템 요구 사항에 따라 다릅니다.

  • 읽기만하면
  • 월말에
  • 시작일에 일부 사용자의 경우
  • ...

1
그러면 어떻게 오래된 대기열에 들어가게됩니까?
jcolebrand

2
@jcolebrand .. 일부 위젯에 대한 등급 (등급 테이블)을 삽입 / 삭제하는 순간. 현재 Widgets 테이블의 평균값이 유효하지 않게되므로 widget_id라는 하나의 열만있는 StaleWidgets 레코드를 테이블에 삽입해야합니다. 등급 테이블 또는 변형 버전에 레코드를 삽입하는 트리거 또는 저장 프로 시저를 사용하십시오.
garik

2

계산이 너무 번거롭지 않고 계산이 복잡하고 업데이트가 자주 있지만 계산 된 데이터를 저장할 수 있고 재 계산이 필요한지 여부를 저장하는 여분의 열 (bool)보다 빈번한 읽기가 아닌 경우 즉시 계산을 제안합니다. . 예를 들어, 재 계산을 수행해야하지만 재 계산을 수행하지 않을 때마다이 열을 true로 설정하고 재 계산을 수행 할 때이 열을 false로 설정하십시오 (계산 된 값이 최신이며 오래되지 않음).

이렇게하면 매번 다시 계산할 필요가 없으며 열 값을 읽고 다시 계산해야 할 때만 계산됩니다. 이렇게하면 많은 재 계산이 절약됩니다.


2

특히 모든 등급을 추가하고 평균으로 나눌 필요가없는 다른 솔루션이 있습니다. 대신 총 리뷰 수를 포함하는 다른 필드를 가질 수 있으므로, 등급을 추가 할 때마다 (avg_rating × total + new_rating) / total을 사용하여 새 평균을 계산할 때마다 집계보다 훨씬 빠르며 디스크 읽기가 줄어 듭니다. 모든 등급 값에 액세스 할 필요는 없습니다. 다른 경우에도 비슷한 해결책이 적용될 수 있습니다.

이것의 단점은 산성 거래가 아니기 때문에 오래된 등급으로 끝날 수 있다는 것입니다. 그러나 여전히 데이터베이스에서 트리거를 사용하여이를 해결할 수 있습니다. 다른 문제는 데이터베이스가 더 이상 정규화되지 않지만 성능과 비교하여 데이터를 비정규 화하는 것을 두려워하지 않는다는 것입니다.

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