1

나는 두 개의 테이블에서 모든 데이터를 가져 와서 어떤 것을 다시 계산하고 저장하는 클라이언트 - 서버 애플리케이션을 가지고있다.DB 디자인/대기 시간/동시성, 끔찍한 두통

예 :

각 항목이 '빌 재료」를 가지는 목록이 부족되어있는 다른 상품의 수량을 =. 따라서 항목 비용은 해당 항목의 BOM * 수량에 대한 비용 합계입니다. 궁극적으로 일부 "기본"항목에는 BOM이없고 비용 만 별도로 설정됩니다. (예 : 원자재)

예 : A의 BOM은 2xB 및 3xC로 구성됩니다.

내가 지금하고있는 것과 내가 왜 이런 식으로 기억하는지 모르겠다. DB에서 모든 항목과 모든 BOM을 가져 와서 재귀 적으로 비용을 계산할 때마다 각 항목을 가져 간다. 한 항목을 계산하면 다시 플래그를 다시 지정하지 않으므로 플래그를 지정합니다. (또한 무한 재귀를 막아 준다)

이것은 다소 어리석은 일이다 : 우선, 그 슬 루우와 변경되지 않은 물건을 다시 계산하고, 더 큰 DB를주고, 메모리가 부족할 것이다. .

대신 항목의 BOM이 변경되면 해당 BOM을 다시 계산 한 다음이 업데이트 된 항목이 포함 된 모든 BOM을 선택하고 다시 계산할 수도 있습니다. 린스 및 반복적으로 반복적으로 반복합니다. DB의 BOM은 변경된 항목에 따라 달라집니다.

실제로 의미하는 바는 일부 품목이 원자재이며 비용이 자주 업데이트 될 수 있으며 일부 품목은 "최종 사용자"물건이며 BOM은 거의 변경되지 않을 것이라고합니다. 사용자가 이러한 자료 중 하나의 비용을 변경하면 수천 개의 항목을 골라서 다시 계산할 수 있습니다. 1 항목/BOM의 SELECT가 15ms (Postgresql에 있음)를 선택한 다음 1000 항목/BOM을 선택하는 데 15 초가 걸린 다음 재 계산 된 비용을 DB의 항목으로 다시 업데이트해야한다고 ... 사랑 스러울 때 대기 시간은 이제 몇 분으로 바뀔 수 있습니다.

내가 사용하는 회사의 ERP 소프트웨어는 첫 번째 접근 방식을 취합니다. 전체 DB를 한 번에 다시 계산하십시오. 이것은 글자 그대로 몇 시간이 걸리며, 10 년 이상의 사용으로이 접근 방식으로 문제가 형성되고있는 것처럼 보입니다. 배치 재 계산은 매주 수행됩니다.

이제 실제로 "이 내용을 큰 소리로 써"보았으므로 몇 분이 지나면 문제가 너무 많다고 생각하지 않습니다. 문제는 데이터베이스를 잘 이해하지 못하기 때문에 동시성에 대해 걱정하고 있습니다. 항목 A에서 업데이트하는 데 오랜 시간이 걸리므로 누군가가 항목 A가있는 동안 두 번째 항목 B를 업데이트 할 가능성이 있습니다 업데이트되었습니다.

말 항목 D는 위의 A와 B로 구성됩니다. 사용자 1은 A를 업데이트하므로 서버 소프트웨어는 DB로 수음을 시작하여 결국 D를 업데이트합니다. 그러나 그 동안 사용자 2는 B를 업데이트하므로 결국 서버에서 D를 다시 업데이트합니다.

PostgreSQL의 트랜잭션을 사용하면 문제가 해결됩니까? 트랜잭션은 그 당시의 DB 상태로 시작하므로 트랜잭션 1은 D가 A1과 B1로 만들어지고 A가 A1에서 A2로 업데이트되는 것을 보지만 트랜잭션이 완료되고 커밋되기 전에 트랜잭션 2가 시작되고 A1도 보입니다. 및 B1. T1은 다시 계산하고 커밋하며 D = A2 + B1입니다. 그러나 T2는 이미 시작되었고 새로운 A, A2를 보지 못했습니다. 그래서 DB에 D = A1 + B2라는 커밋을합니다. 그것은 D = A2 + B2 여야합니다.

또한 일부 처리가 중복되어 서버 시간이 낭비됩니다.

평행 대신 T1과 T2를 순차적으로 수행하면 만세, 대답은 정확하지만 사용자 2는 더 오래 기다려야합니다. 또한, 트랜잭션 그룹이 서로 독립적이지 않은 경우 (즉, A = X + Y 및 B = N + M), 병렬 계산은 정답을 제공하고 사용자.

중요 사항 : 순차적으로 처리 할 때도 여전히 트랜잭션을 사용하므로 나머지 소프트웨어는 비용을 다시 계산하는 함수를 제외하고는 해당 데이터와 병렬로 계속 작동 할 수 있습니다.

DB 대기 시간이 너무 "끔찍한"것이 아니라면,이 모든 "순차적 처리"는 그렇게 나쁘지 않을 것입니다. 말하자면, 전체 데이터가 RAM에 저장된다면, 물마루 천 물체가 산들 바람이 될 것입니다. 아,하지만 디스크/RAM에서 /로 데이터를 빠르게 이동하고 DB를 대체하기 위해 캐싱을 수행하는 시스템을 구축하더라도 여전히 서버 기능의 나머지 부분을 처리 할 수 ​​있도록 트랜잭션이 필요하기 때문에 그렇게하지 않을 것입니다. 병렬로 작업 할 수 있습니다. (위의 '중요한 메모') 그래서 나는 또 다른 DB를 구축하게 될 것입니다. 조금 더 빨라지 겠지만 어리석은/시간 낭비.

각 항목의 비용을 "캐시"하는 이유는 제한된 리소스를 낭비 할뿐만 아니라 DB 대기 시간이 너무 크고 동시성 문제이기 때문에 사용할 때마다 다시 계산하지 않기 때문입니다. 규모가 더 나 빠졌다.

이제 "그들이"큰 일괄 처리를 한 이유가 무엇인지 궁금 할 필요가 없습니다 ... 이것은 내 머리를 아프게하고 있습니다.

Q1 : 어떻게 당신이 "최적"의 방법으로이 문제를 해결합니까?

내 이해 (즉, 내가 조용히 무시하기 전에 동시성 문제에 직면 한 후), 나는 그 함수가 순차적으로 트랜잭션을 사용하도록 만들 것이고, 나머지 응용 프로그램은 여전히 ​​데이터를 사용할 수 있습니다. 평행, 내가 믿는 사용자에게 가장 좋습니다. 그게 목표입니다. 사용자에게는 가장 좋지만 시스템에 대한 정확성은 보장됩니다.

어쩌면 나중에 하드웨어를 던져서 소프트웨어 블랙 매직을 사용하여 지연 시간을 줄일 수 있지만 지금은 스스로 거짓말하기 시작합니다.

지난 두 달 동안 나는 프로그래밍에 관련되지 않은 여러 가지 명백한 일들에 대해 완전히 눈이 멀었습니다. 그래서 누군가 내가 부끄러워 보이는 것을 지적 할 것입니다. 놓치다 : ... |

답변

4

이 같은 그것을 왜 내가 기억하지 않습니다 ...

이를 해결하기 위해 가장 먼저해야 할 일이 같은 날 밖으로 점프!

각 BOM의 총 비용을 계산하기 위해 데이터를 애플리케이션으로 다시 가져와야하는 이유가 없어야합니다. "부품 폭발"또는 SQL의 계층 적 데이터 세트로 작업 할 수있는 많은 기술이 있습니다.

내 프레젠테이션 "SQL Antipatterns Strike Back"에서 여러 가지 해결책을 제시하거나 "Joe Celko's Trees and Hierarchies in SQL"과 같은 책을 읽을 수 있습니다.

일부 솔루션은 공급 업체별이며 일부는 일반 SQL DBMS로 수행 할 수 있습니다. 나는 데이터베이스의 어떤 브랜드인지 알지 못했지만 Jonathan은 PostgreSQL을 사용하고 있음을 올바르게 인식하고 있습니다.

그런 경우 PostgreSQL 8.4의 새로운 기능인 "WITH"쿼리를 읽고 정교한 재귀 쿼리 효과를 수행 할 수 있습니다.

http://www.postgresql.org/docs/current/static/queries-with.html

내가 BOM의 개별 자원의 계층 구조로 구성 된 시스템을 구현했습니다, 나는 당신이 틀림없이 (기술하고있는 일괄 처리 작업을 수행 할 필요가 없었다, 단지 몇 있었다 내가 그것에 대해 연구하는 동안 데이터베이스에 수천 개의 리소스가 있음).

SUM()GROUP BY과 같은 집계 함수를 사용하는 방법 (SQL에 대한 모든 책에이 책을 포함해야 함)과 엔티티의 계층 적 관계를 저장하는 기술을 배워야합니다.

데이터베이스를 잘 이해하지 못한다고 말하면서 실제 시스템을 변경하기 전에 "장난감"시스템을 구현하는 것이 좋습니다. 저는 개인적인 경험으로 만 이야기하고 있습니다 만, 새로운 기술 스킬을 배울 수는 없지만 동시에 실제 프로젝트에서 그 스킬을 사용하려고합니다.

+0

그는 한 지점에서 "나는 PostgreSQL에있다"고 언급하고 있습니다 ... –

+0

죄송합니다! 나는 그것을 놓쳤다. –

2

데이터베이스의 저장 프로 시저에서 이익을 얻을 수있는 계산 방법은 어떤 구현 방법을 사용하든 관계없이 다소 나을 것 같습니다. 이는 클라이언트와 서버 사이의 트래픽을 줄여 주며 거의 항상 이와 같은 복잡한 계산 집합의 성능을 향상시킵니다.

당신 말 :

, 내가 DB에서 모든 항목 모든 BOM을 얻고, 각각에 가서 내가 지금, 나는 이런 식으로 그것을 왜 기억하지 못하는 것입니다

항목을 재귀 적으로 비용을 계산합니다. 한 항목을 계산하면 다시 플래그를 다시 지정하지 않으므로 플래그를 지정합니다. (또한 무한 재귀를 막습니다).

나는이 설명의 일부인 '국기'에 대해 당혹 스럽다. 왜 그런 행동을하는 것이 나쁜 소식인지 알지 못한다. 당신이하는 일을 정말로 이해해야합니다.

BOM 처리에는 여러 가지 방법이 있습니다. Bill Karwin은 몇 가지 흥미로운 정보를 지적했습니다 (SQL Antipatterns 링크는 약 250 개의 슬라이드입니다!). SQL Antipatterns 섹션에서는 '순진한 나무'(아래에 설명 된 것과 같은)에 대해 설명합니다. 그러나 솔루션은 하위 트리가 여러 부모에 의해 사용될 수있는 경우 (하나의 하위 어셈블리가 여러 제품의 구성 요소 일 수 있기 때문에) 아래에 설명 된 사례를 다루지는 않습니다.

  • 경로 열거가 작동하지 않습니다. 경로에 포함 된 제품 정보를 작성하기 때문에 동일한 하위 어셈블리 정보를 사용할 수 없습니다.
  • 중첩 세트는 서브 어셈블리가 한 제품에서 사용될 때 잘 작동합니다. 서브 어셈블리가 많은 제품에 사용되는 경우가 아닙니다.
  • '클로저 테이블'솔루션은 이것을 덮기 위해 적용될 수 있습니다. 아래에서 두 번째 대안이 될 수 있습니다.

영향을받는 부품에 대해 상향식 스캔을 수행하는 것이 좋으며 또는 폭 - 우선 또는 깊이 우선 스캔을 수행하는 것이 더 나을지 여부를 고려해야합니다. 이 결정을 내리는 한 가지 드라이버는 BOM 데이터의 성격 일 것입니다. 일부 하위 어셈블리가 여러 제품의 구성 요소로 사용되는 구조가있는 경우 각 제품에 대해 하위 어셈블리에 부품 사용을 개별적으로 기록합니까? 아니면 하위 어셈블리를 사용하는 제품을 기록합니까?

가 명확히 :

  • 서브 어셈블리 A (P001)을 24 X 8mm 너트 (P002) 24 X 8mm × 50 밀리 볼트 (P003), 1 ×베이스 플레이트 (P004), 1 ×의 coverplate 포함 (P005).
  • 제품 B (P006)에는 1 x 서브 어셈블리 A와 기타 여러 부품이 들어 있습니다.
  • 제품 B (P007)에는 1 x 서브 어셈블리 B와 기타 여러 부품이 들어 있습니다. 이 (순진 나무)처럼 보일 수

귀하의 BOM 기록 :

Part  Component  Quantity 
P001  P002   24 
P001  P003   24 
P001  P004   1 
P001  P005   1 
P006  P001   1 
P007  P001   1 

아니면이 (폐쇄 테이블)처럼 보일 수 :

Part  Component  Quantity 
P001  P002   24 
P001  P003   24 
P001  P004   1 
P001  P005   1 
P006  P002   24 
P006  P003   24 
P006  P004   1 
P006  P005   1 
P007  P002   24 
P007  P003   24 
P007  P004   1 
P007  P005   1 

이 두 번째 경우는 훨씬 덜 바람직하다 - 너트 나 볼트 같은 부품의 경우와 같이 여러 하위 어셈블리가 동일한 부품을 사용할 수 있으므로 주요 산출물 (P006, P007)에서 바로 카운트를 얻으려면 값을 올바르게 입력하는 것이 더 어렵습니다.) 매우 어려울 것입니다. 그러나 두 번째 경우에는 부품 비용을 다시 계산하는 것이 훨씬 간단합니다. 부품을 구성하는 각 부품에 대한 '비용 시간 수량'의 합계를 계산하면됩니다. 일부 제품 또는 하위 어셈블리의 구조 (가격이 아님)가 변경 될 때 부분 구조 분석을 기록하고 클로저 테이블을 재 계산 (다시 계산) 할 순진한 트리를 유지하면 가능성이 높기 때문에 너바나에 가까울 것입니다 얻을.

어딘가에 (하지만이 컴퓨터가 아닌 다른 컴퓨터에서) 나는 가상의 어셈블리를 사용하여이 물건을 뒤죽박죽으로 사용할 수있는 오래된 코드가 있습니다. 코딩이 완료되었습니다 ... 오래 전부터, 특정 DBMS에 대한 임시 테이블을 사용합니다 (중첩 세트 또는 경로 열거는 언급하지 않고 클로저 테이블을 계산합니다). 다른 DBMS에 적합합니다. 물어 보자. 나는 그것을 파헤쳐 볼 것이다.