문제

두 개의 테이블이 있는데 외부 소스에서 이 테이블에 레코드가 지속적으로 삽입됩니다.이 테이블이 사용자 상호 작용에 대한 통계를 유지하고 있다고 가정해 보겠습니다.사용자가 버튼을 클릭하면 해당 클릭에 대한 세부 정보(사용자, 클릭 시간 등)가 테이블 중 하나에 기록됩니다.사용자가 해당 버튼 위에 마우스를 올리면 다른 테이블에 세부정보가 포함된 기록이 추가됩니다.

시스템과 지속적으로 상호 작용하는 사용자가 많으면 많은 데이터가 생성되고 해당 테이블이 엄청나게 커질 것입니다.

데이터를 보고 싶을 때 시간별 또는 일별 해상도로 보고 싶습니다.

요구되는 해결 방법으로 데이터를 점진적으로(데이터가 수집됨에 따라) 지속적으로 요약하는 방법이나 모범 사례가 있습니까?

아니면 이런 종류의 문제에 대한 더 나은 접근 방식이 있습니까?

추신.지금까지 내가 찾은 것은 Talend와 같은 ETL 도구가 삶을 쉽게 만들어 줄 수 있다는 것입니다.

업데이트:현재 MySQL을 사용하고 있는데 DB, 환경 등에 관계없이 모범 사례가 궁금합니다.

도움이 되었습니까?

해결책

지연 시간이 짧은 데이터 웨어하우스 애플리케이션에서 이를 수행하는 일반적인 방법은 빠르게 업데이트할 수 있는 항목이 포함된 선행 파티션이 있는 분할된 테이블을 갖는 것입니다(예:즉석에서 집계를 다시 계산할 필요 없이) 후행 파티션이 집계로 다시 채워집니다.즉, 선행 파티션은 후행 파티션과 다른 저장 구성표를 사용할 수 있습니다.

대부분의 상용 및 일부 오픈 소스 RDBMS 플랫폼(예:PostgreSQL)은 이러한 유형의 작업을 어떤 방식으로든 수행하는 데 사용할 수 있는 분할된 테이블을 지원할 수 있습니다.로그에서 데이터베이스를 채우는 방법은 독자의 연습 문제로 남겨집니다.

기본적으로 이러한 유형의 시스템 구조는 다음과 같습니다.

  • 일부 테이블에 분할된 테이블이 있습니다 날짜 또는 날짜/시간 값의 종류입니다, 시간, 요일 등으로 분할 곡물이 적절해 보입니다.로그 항목이 이 테이블에 추가됩니다.

  • 시간 창이 파티션, 주기적인 작업 인덱스 또는 를 요약하여 다음과 같이 변환합니다 '동결' 상태입니다.예를 들어 오라클의 작업은 비트맵을 생성할 수 있습니다 인덱스를 생성하거나 해당 파티션의 요약이 포함된 구체화된 보기 해당 파티션의 데이터.

  • 나중에 오래된 데이터를 삭제할 수 있습니다, 요약 또는 파티션 병합 함께.

  • 시간이 지남에 따라 정기적인 작업 앞쪽 가장자리 뒤로 채우기 파티션.기록 데이터는 다음과 같습니다 대여 가능한 형식으로 변환 자체에 대한 성능 통계 쿼리를 실행하는 동안 전면 가장자리 파티션은 쉽게 업데이트할 수 있도록 유지됩니다 빠르게.이 파티션은 너무 많은 데이터를 보유하여 전체 데이터 세트가 상대적으로 빠르게.

이 프로세스의 정확한 특성은 DBMS 플랫폼마다 다릅니다.

예를 들어, SQL Server의 테이블 분할은 그다지 좋지 않지만 Analysis Services(Microsoft가 SQL Server와 함께 번들로 제공하는 OLAP 서버)를 사용하여 수행할 수 있습니다.이는 선행 파티션을 순수 ROLAP(OLAP 서버는 기본 데이터베이스에 대해 쿼리를 실행함)로 구성한 다음 후행 파티션을 MOLAP(OLAP 서버는 '집계'라고 알려진 영구 요약을 포함하여 고유한 특수 데이터 구조를 구성함)로 다시 구성함으로써 수행됩니다. ).분석 서비스는 이를 사용자에게 완전히 투명하게 수행할 수 있습니다.이전 ROLAP 파티션이 사용자에게 계속 표시되는 동안 백그라운드에서 파티션을 재구축할 수 있습니다.빌드가 완료되면 파티션에서 교체됩니다.큐브는 사용자에 대한 서비스 중단 없이 항상 사용 가능합니다.

Oracle에서는 파티션 구조를 독립적으로 업데이트할 수 있으므로 인덱스를 생성하거나 구체화된 뷰에 파티션을 구축할 수 있습니다.쿼리 재작성을 사용하면 Oracle의 쿼리 최적화 프로그램은 기본 팩트 테이블에서 계산된 집계 수치를 구체화된 뷰에서 얻을 수 있도록 작업할 수 있습니다.쿼리는 파티션을 사용할 수 있는 구체화된 뷰와 그렇지 않은 선행 에지 파티션에서 집계 수치를 읽습니다.

PostgreSQL도 이와 유사한 기능을 수행할 수 있지만 저는 PostgreSQL에 이러한 유형의 시스템을 구현해 본 적이 없습니다.

주기적인 중단이 발생할 수 있는 경우 요약을 수행하고 선행 및 후행 데이터에 대한 보기를 설정하여 유사한 작업을 명시적으로 수행할 수 있습니다.이를 통해 투명한 분할을 지원하지 않는 시스템에서 이러한 유형의 분석을 수행할 수 있습니다.그러나 뷰가 다시 작성되면서 시스템이 일시적으로 중단되므로 업무 시간 중에는 실제로 이 작업을 수행할 수 없습니다. 대부분 밤샘이 될 것입니다.

편집하다: 로그 파일의 형식이나 사용 가능한 로깅 옵션에 따라 데이터를 시스템에 로드하는 다양한 방법이 있습니다.일부 옵션은 다음과 같습니다:

  • 데이터를 읽고 관련 비트를 구문 분석하여 데이터베이스에 삽입하는 선호하는 프로그래밍 언어를 사용하여 스크립트를 작성하십시오.이는 상당히 자주 실행될 수 있지만 파일에서 현재 위치를 추적할 수 있는 방법이 있어야 합니다.특히 Windows에서는 잠금에 주의하세요.Unix/Linux의 기본 파일 잠금 의미 체계를 사용하면 이 작업을 수행할 수 있습니다. tail -f 작동함) 그러나 Windows의 기본 동작은 다릅니다.두 시스템 모두 서로 잘 작동하도록 작성되어야 합니다.

  • Unix-oid 시스템에서는 로그를 파이프에 기록하고 파이프에서 읽는 위의 프로세스와 유사한 프로세스를 가질 수 있습니다.이는 대기 시간이 가장 낮지만 리더기의 오류로 인해 애플리케이션이 차단될 수 있습니다.

  • 로그 파일을 작성하는 대신 데이터베이스를 직접 채우는 애플리케이션용 로깅 인터페이스를 작성하세요.

  • 데이터베이스에 대한 대량 로드 API를 사용하고(대부분의 경우 이러한 유형의 API를 사용할 수 있음) 로깅 데이터를 일괄적으로 로드합니다.첫 번째 옵션과 유사한 프로그램을 작성하되 대량 로드 API를 사용하십시오.이는 한 줄씩 채우는 것보다 적은 리소스를 사용하지만 대량 로드를 설정하는 데 더 많은 오버헤드가 있습니다.로드 빈도를 줄이는 것이 적합하며(매시간 또는 매일) 시스템 전체에 부담을 덜 줍니다.

대부분의 시나리오에서는 자신이 어디에 있었는지 추적하는 것이 문제가 됩니다.변경 사항을 찾기 위해 파일을 폴링하는 것은 실현 불가능할 정도로 비용이 많이 들 수 있으므로 로그 판독기와 원활하게 작동하도록 로거를 설정해야 할 수도 있습니다.

  • 한 가지 옵션은 로거를 변경하여 매 기간(예: 몇 분마다)마다 다른 파일에 쓰기를 시작하는 것입니다.로그 판독기를 주기적으로 시작하고 아직 처리되지 않은 새 파일을 로드하도록 하십시오.이전 파일을 읽으십시오.이것이 작동하려면 독자가 어떤 파일을 선택할지 알 수 있도록 파일의 명명 체계가 시간을 기반으로 해야 합니다.응용 프로그램에서 아직 사용 중인 파일을 처리하는 것은 더 까다로우므로(그런 다음 읽은 양을 추적해야 합니다) 마지막 기간까지만 파일을 읽는 것이 좋습니다.

  • 또 다른 옵션은 파일을 이동한 다음 읽는 것입니다.이는 Unix 시스템처럼 작동하는 파일 시스템에서 가장 잘 작동하지만 NTFS에서도 작동해야 합니다.파일을 이동한 다음 여유롭게 읽으십시오.그러나 로거는 생성/추가 모드에서 파일을 열고 파일에 쓴 다음 닫아야 합니다. 파일을 열고 잠긴 상태로 유지하는 것이 아닙니다.이것은 확실히 Unix 동작입니다. 이동 작업은 원자적이어야 합니다.Windows에서는 이 작업을 수행하려면 실제로 로거 위에 서 있어야 할 수도 있습니다.

다른 팁

보세요 rrdtool. 라운드 로빈 데이터베이스입니다. 캡처하려는 메트릭을 정의하지만 저장 한 해상도를 정의 할 수도 있습니다.

예를 들어, LAS 시간에 대해 지정할 수 있으며 매 초의 정보를 유지할 수 있습니다. 지난 24 시간 동안 - 매 순간; 지난 주, 매 시간마다 등

다음과 같은 시스템에서 통계를 수집하는 데 널리 사용됩니다. 신경절 그리고 선인장.

(시간 등을 기준으로) 데이터를 분할하고 집계하는 경우 스타 스키마(Kimball star)는 매우 간단하면서도 강력한 솔루션입니다.각 클릭에 대해 시간(초 해상도), 사용자 정보, 버튼 ID 및 사용자 위치를 저장한다고 가정합니다.쉽게 슬라이싱하고 다이싱할 수 있도록 거의 변경되지 않는 개체의 속성에 대해 미리 로드된 조회 테이블(DW 세계에서는 차원 테이블이라고 함)부터 시작하겠습니다.

pagevisit2_model_02

그만큼 dimDate 테이블에는 특정 날짜를 설명하는 여러 속성(필드)이 포함된 각 날짜에 대한 하나의 행이 있습니다.테이블은 몇 년 전에 미리 로드할 수 있으며 다음과 같은 필드가 포함된 경우 하루에 한 번씩 업데이트해야 합니다. DaysAgo, WeeksAgo, MonthsAgo, YearsAgo;그렇지 않으면 "로드 후 잊어버리기"가 될 수 있습니다.그만큼 dimDate 다음과 같은 날짜 속성별로 쉽게 분할할 수 있습니다.

WHERE [YEAR] = 2009 AND DayOfWeek = 'Sunday'

10년 동안의 데이터에 대해 테이블에는 최대 3,650개의 행만 있습니다.

그만큼 dimGeography 테이블에는 관심 지역이 미리 로드되어 있습니다. 행 수는 보고서에 필요한 "지리적 해상도"에 따라 달라지며 다음과 같은 데이터 분할이 가능합니다.

WHERE Continent = 'South America'

일단 로드되면 거의 변경되지 않습니다.

사이트의 각 버튼에 대해 희미한 버튼 테이블에 하나의 행이 있으므로 쿼리에는 다음이 있을 수 있습니다.

WHERE PageURL = 'http://…/somepage.php'

그만큼 dimUser 테이블에는 등록된 사용자당 하나의 행이 있습니다. 이 행은 사용자가 등록하자마자 새 사용자 정보와 함께 로드되어야 합니다. 또는 최소한 다른 사용자 트랜잭션이 팩트 테이블에 기록되기 전에 새 사용자 정보가 테이블에 있어야 합니다.

버튼 클릭을 기록하기 위해 factClick 테이블.

pagevisit2_model_01

그만큼 factClick 테이블에는 특정 시점에 특정 사용자가 버튼을 클릭할 때마다 행이 하나씩 있습니다.나는 사용했다 TimeStamp (두 번째 해결 방법), ButtonKey 그리고 UserKey 특정 사용자의 클릭을 초당 1회보다 빠르게 필터링하기 위해 복합 기본 키를 사용합니다.참고하세요 Hour 필드에는 시간 부분이 포함되어 있습니다. TimeStamp, 시간당 쉽게 슬라이싱할 수 있도록 0-23 범위의 정수입니다.

WHERE [HOUR] BETWEEN 7 AND 9

이제 우리는 다음을 고려해야 합니다.

  • 테이블을 로드하는 방법은 무엇입니까?ETL 도구를 사용하는 웹로그나 일종의 이벤트 스트리밍 프로세스를 사용하는 지연 시간이 짧은 솔루션에서 주기적으로(매시간 또는 몇 분마다).
  • 테이블에 있는 정보를 얼마나 오래 보관하나요?

테이블이 하루 동안만 정보를 보관하는지, 아니면 몇 년 동안만 보관하는지에 관계없이 파티션을 나누어야 합니다. ConcernedOfTunbridgeW 그의 답변에서 분할을 설명했으므로 여기서는 건너뛰겠습니다.

이제 다양한 속성(요일 및 시간 포함)별로 슬라이싱 및 다이싱하는 몇 가지 예를 살펴보겠습니다.

쿼리를 단순화하기 위해 모델을 평면화하는 뷰를 추가하겠습니다.

/* To simplify queries flatten the model */ 
CREATE VIEW vClicks 
AS 
SELECT * 
FROM factClick AS f 
JOIN dimDate AS d ON d.DateKey = f.DateKey 
JOIN dimButton AS b ON b.ButtonKey = f.ButtonKey 
JOIN dimUser AS u ON u.UserKey = f.UserKey 
JOIN dimGeography AS g ON g.GeographyKey = f.GeographyKey

쿼리 예시

/* 
Count number of times specific users clicked any button  
today between 7 and 9 AM (7:00 - 9:59)
*/ 
SELECT  [Email] 
       ,COUNT(*) AS [Counter] 
FROM    vClicks 
WHERE   [DaysAgo] = 0 
        AND [Hour] BETWEEN 7 AND 9 
        AND [Email] IN ('dude45@somemail.com', 'bob46@bobmail.com') 
GROUP BY [Email] 
ORDER BY [Email]

내가 다음에 대한 데이터에 관심이 있다고 가정해 보겠습니다. User = ALL.그만큼 dimUser 은 큰 테이블이므로 쿼리 속도를 높이기 위해 테이블 ​​없이 뷰를 만들겠습니다.

/* 
Because dimUser can be large table it is good 
to have a view without it, to speed-up queries 
when user info is not required 
*/ 
CREATE VIEW vClicksNoUsr 
AS 
SELECT * 
FROM factClick AS f 
JOIN dimDate AS d ON d.DateKey = f.DateKey 
JOIN dimButton AS b ON b.ButtonKey = f.ButtonKey 
JOIN dimGeography AS g ON g.GeographyKey = f.GeographyKey

쿼리 예시

/* 
Count number of times a button was clicked on a specific page 
today and yesterday, for each hour. 
*/ 
SELECT  [FullDate] 
       ,[Hour] 
       ,COUNT(*) AS [Counter] 
FROM    vClicksNoUsr 
WHERE   [DaysAgo] IN ( 0, 1 ) 
        AND PageURL = 'http://...MyPage' 
GROUP BY [FullDate], [Hour] 
ORDER BY [FullDate] DESC, [Hour] DESC



다음과 같이 가정해보자 집계 특정 사용자 정보를 유지할 필요는 없지만 날짜, 시간, 버튼 및 지역에만 관심이 있습니다.각 행의 factClickAgg 테이블에는 특정 지역에서 특정 버튼을 클릭한 각 시간에 대한 카운터가 있습니다.

pagevisit2_model_03

그만큼 factClickAgg 보고 및 분석 요구 사항에 따라 테이블은 매시간 또는 하루가 끝날 때 로드될 수 있습니다.예를 들어, 매일 업무가 끝날 때(자정 이후) 테이블이 로드된다고 가정하면 다음과 같이 사용할 수 있습니다.

/* At the end of each day (after midnight) aggregate data. */ 
INSERT  INTO factClickAgg 
        SELECT  DateKey 
               ,[Hour] 
               ,ButtonKey 
               ,GeographyKey 
               ,COUNT(*) AS [ClickCount] 
        FROM    vClicksNoUsr 
        WHERE   [DaysAgo] = 1 
        GROUP BY DateKey 
               ,[Hour] 
               ,ButtonKey 
               ,GeographyKey

쿼리를 단순화하기 위해 모델을 평면화하는 뷰를 생성하겠습니다.

/* To simplify queries for aggregated data */ 
CREATE VIEW vClicksAggregate 
AS 
SELECT * 
FROM factClickAgg AS f 
JOIN dimDate AS d ON d.DateKey = f.DateKey 
JOIN dimButton AS b ON b.ButtonKey = f.ButtonKey 
JOIN dimGeography AS g ON g.GeographyKey = f.GeographyKey

이제 집계된 데이터(예: 일별)를 쿼리할 수 있습니다.

/* 
Number of times a specific buttons was clicked 
in year 2009, by day 
*/ 
SELECT  FullDate 
       ,SUM(ClickCount) AS [Counter] 
FROM    vClicksAggregate 
WHERE   ButtonName = 'MyBtn_1' 
        AND [Year] = 2009 
GROUP BY FullDate 
ORDER BY FullDate

또는 몇 가지 옵션이 더 있습니다.

/* 
Number of times specific buttons were clicked 
in year 2008, on Saturdays, between 9:00 and 11:59 AM 
by users from Africa 
*/ 

SELECT  SUM(ClickCount) AS [Counter] 
FROM    vClicksAggregate 
WHERE   [Year] = 2008 
        AND [DayOfWeek] = 'Saturday' 
        AND [Hour] BETWEEN 9 AND 11 
        AND Continent = 'Africa' 
        AND ButtonName IN ( 'MyBtn_1', 'MyBtn_2', 'MyBtn_3' )

PI 또는 역사가와 같은 역사적인 DB를 사용할 수 있습니다. 이 프로젝트에 쓰고 싶은 것보다 더 많은 돈이 될 수 있으므로, 당신은 실시간 및 히스토리 데이터베이스 패키지.

빠른 '더러운 제안.

기본 테이블을 변경할 수 없다고 가정하면 해당 테이블이 이미 시간/날짜 행을 기록하고 DB에서 객체를 만들 수있는 권한이 있다고합니다].

  1. 논리 필드가있는 뷰 (또는 몇 가지보기)를 만듭니다.이 필드는 테이블에서 날짜를 자르면 독특한 '슬롯 덤프'를 생성합니다. 같은 것 :

테이블에서 select a, b, c, substr (date_field, x, y) slot_number로보기를 작성하십시오.

위의 예는 단순화되며 날짜+시간에서 더 많은 요소를 추가하고 싶을 것입니다.

예를 들어, 날짜는 '2010-01-01 10 : 20 : 23,111'이라고 말하면 '2010-01-01 10:00'로 열쇠를 생성 할 수 있습니다. 따라서 해상도는 1 시간입니다].

  1. 선택적으로 :보기를 사용하여 실제 테이블을 생성합니다.

    slot_number = 'xxx;

왜 1 단계를 귀찮게합니까? 실제로 볼 필요는 없습니다.보기를 사용하면 SQL 관점에서 조금 더 쉬워 질 수 있습니다.

왜 2 단계를 귀찮게합니까? 이미 바쁜 테이블에서 하중을 줄이는 방법 : DDL을 동적으로 생성 할 수 있다면 데이터의 '슬롯'사본으로 별도의 테이블을 생성 할 수 있습니다.

또는 하루에 하나씩 테이블 그룹을 설정할 수 있습니다. 2 차 테이블을 채우기위한 트리거를 만듭니다. 트리거의 논리는 어떤 테이블이 작성되었는지를 알 수 있습니다.

매일이 테이블을 재설정해야합니다. DB의 트리거에서 테이블을 생성 할 수 없다면. [내가 생각하지 않을 것 같지].

지금까지 제공되지 않은 제안은 couchdb 또는 구조화되지 않은 데이터를 다루는 유사한 데이터베이스 개념.

기다리다! 공포로 나를 뛰어 넘기 전에 마무리하겠습니다.

CouchDB는 구조화되지 않은 데이터 (JSON & C)를 수집합니다. 웹 사이트에서 기술 개요를 인용하고

CouchDB는 구조적 및 반 구조화 된 데이터에 구조를 추가하는이 문제를 해결하기 위해보기 모델을 통합합니다. 보기는 데이터베이스의 문서를 집계하고보고하는 방법이며 데이터베이스 문서를 집계, 가입 및보고하기 위해 주문형 구축됩니다. 보기는 동적으로 구축되며 기본 문서에 영향을 미치지 않으므로 원하는 것과 동일한 데이터의 다양한보기 표현을 가질 수 있습니다.

보기 정의는 엄격하게 가상이며 현재 데이터베이스 인스턴스의 문서 만 표시하므로 표시가 표시되고 복제와 호환됩니다. CouchDB 뷰는 특수 설계 문서 내부에 정의되며 일반 문서와 같은 데이터베이스 인스턴스에서 복제 할 수 있으므로 CouchDB에서 데이터가 복제 될뿐만 아니라 전체 응용 프로그램 디자인도 복제됩니다.

귀하의 요구 사항에서, 나는 당신에게 필요를 말할 수 있습니다

  • 신뢰할 수있는 방법으로 많은 데이터를 수집합니다
  • 우선 순위는 시스템에 들어가 자마자 데이터를 구조화하거나 수집 한 내용의 구조적 특성을 유지/점검하는 것이 아니라 속도/신뢰성에 있습니다 (사용자 데이터 1ms를 놓치더라도 큰 문제가 아닐 수도 있음).
  • 구조화 된 데이터가 올 때 구조화 된 데이터가 필요합니다 밖으로 DB의

개인적으로, 나는 다음과 같은 일을 할 것입니다.

  • 클라이언트에서 수집 된 데이터 캐시와 CouchDB에 버스트에 저장
  • 워크로드에 따라 DB 클러스터 (다시 CouchDB가이를 위해 설계되었습니다)를 서로 동기화했습니다.
  • 모든 간격에는 서버가 필요한 것들 (즉, 시간마다)을 생성하고 다른 시간에는 데이터를 계속 수집합니다.
  • 이러한 (현재 구조화 된)보기를 조작 및 SQL 도구를 사용하여 재생하기 위해 적절한 데이터베이스에 저장하십시오.

마지막 요점은 예입니다. 나는 당신이 그것으로 무엇을 할 계획인지 전혀 모른다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top