구성 데이터 : 단일 행 테이블 대 이름-값 쌍 테이블


64

사용자가 구성 할 수있는 응용 프로그램을 작성한다고 가정 해 봅시다. 이 "구성 데이터"를 데이터베이스에 저장하기 위해 두 가지 패턴이 일반적으로 사용됩니다.

  1. 단일 행 테이블

      CompanyName  |  StartFullScreen  |  RefreshSeconds  |  ...
    ---------------+-------------------+------------------+--------
      ACME Inc.    |        true       |       20         |  ...
    
  2. 이름 - 값 쌍의 테이블

      ConfigOption   |   Value
    -----------------+-------------
     CompanyName     | ACME Inc.
     StartFullScreen | true (or 1, or Y, ...)
     RefreshSeconds  | 20
     ...             | ...
    

나는 야생에서 두 가지 옵션을 모두 보았으며 두 가지 모두 명백한 장점과 단점이 있습니다.

  • 단일 행 테이블은 사용 가능한 구성 옵션 수를 제한합니다 (일반적으로 행의 열 수는 제한되어 있기 때문에). 모든 추가 구성 옵션에는 DB 스키마 변경이 필요합니다.
  • 이름-값 쌍 테이블에서 모든 것은 "문자열 형식"입니다 (부울 / 날짜 / 등. 매개 변수를 인코딩 / 디코딩해야 함).
  • (많은)

개발 커뮤니티 내에서 어떤 옵션이 선호되는지에 대한 합의가 있습니까?


2
'수직'접근 방식이 다른 데이터 유형을 가질 수있는 이유는 없습니다. 행당 int, float 및 text 열을 추가하십시오. 'SaveConfigInt ('field ', n)'과 같은 유형별 함수를 사용하여 값을 저장 /로드
GrandmasterB

4
이것에 대해 묻는 훌륭한 StackOverflow 질문이 있으며, 가장 좋은 대답은 두 가지 방법 모두에 대한 장단점을 제공합니다. stackoverflow.com/questions/2300356/…
케빈

1
접근 방식 3 : JSON 또는 YAML과 같은 간단한 데이터 교환 형식의 단일 열 / 단일 행 두 가지 접근 방식의 장점을 결합합니다.
schlamar

<config> <CompanyName> ACME Inc. </ CompanyName> <StartFullScreen> true </ StartFullScreen> 20 <RefreshSeconds> </ RefreshSeconds> </ config>와 같이 xml / json을 포함하는 복잡한 데이터에 단일 행 테이블을 사용하는 것은 어떻습니까? 비즈니스 계층에서 개체를 확인 하시겠습니까?
John

1
@ 존 : 계층 구조가 필요한 경우 좋은 생각입니다. 그렇지 않은 경우 복잡성이 추가 된 옵션 2 일뿐입니다.
Heinzi

답변:


15

개인적으로 대부분의 경우 단일 행 테이블을 선호합니다. 유연성이 떨어지는 것은 사실이지만 동적 동작을 기대하지 않는 한 나중에 필요할 경우 추가 열을 추가하는 것이 좋습니다. 어떤 식 으로든, 사전 /지도를 사용하여 이름-값 쌍을 보유하는 것과 프로그래밍 할 때 클래스 멤버를 갖는 것과 같습니다. 물론, 그것은 완벽한 은유는 아니지만, 당신이 그것에 대해 생각할 때 많은 장점과 단점이 병행됩니다.

그래서 반원들에게 사전 /지도를 사용 하시겠습니까? 표현할 데이터의 양이 이름-값 쌍 테이블을 갖는 것처럼 완전히 적응할 수 있다고 생각할 이유가 없다면 아마도 아닐 것입니다.


저장할 데이터가 사용자 정의 된 경우 어떻게합니까? 즉, 사용자가 필드 레이블, 보유 할 데이터 유형 등을 지정하여 "필드"를 작성할 수있는 UI를 생각하십시오. 이는 코드에서 DDL 문을 실행하는 것을 의미합니다. 여전히 옵션 1을 사용 하시겠습니까?
devanalyst

1
@devanalyst 아니오, 데이터가 컴포넌트에서 컴포넌트로 변경 될 수있는 경우이를 나타내는 정적 테이블을 작성하는 것은 의미가 없습니다. 이 경우 두 번째 옵션을 사용하는 것이 좋습니다.
Neil

12

일반적으로 옵션 2를 사용하지만 데이터 유형을 적용하기 위해 여러 열이 있습니다.

ConfigOption   |   textValue    |   DateValue   |   NumericValue

옵션 1 Active열 을 추가하여 전체 구성을 쉽게 "스왑"할 수있는 추가 이점이 있습니다 .


구성을 비활성화하려면 (옵션 1의 경우) 적어도 activatedOn타임 스탬프를 만들어 활성화 시기 를 알 수 있습니다 . 그리고 옵션 2를 사용하는 경우 ... 여러 열에 값을 저장하는 경우 (또는 오라클 인 경우 null과 빈 문자열이 같은 경우) 어떻게됩니까?
Clockwork-Muse

1
@ X-Zero, 다중 구성 저장은 일반적으로 테스트 목적으로 수행되지만 타임 스탬프는 손상되지 않습니다. 당신이 정말로, 당신은 데이터 유형의 컬럼을 추가 할 수 있습니다 싶어하면 구성 유지 보수, 확인하기 위해 무엇을 열 알 것 값을 얻기 위해 전화 ...하지만 난 그 이상 ... 죽일 생각
바부탱

5
EATV (Entity-Attribute-Type-Value) 스키마는 세 번째 정규 형식을 위반합니다. 유형 열은 유형 열이 설명하는 값 열을 통해 테이블의 기본 키와 간접적으로 만 관련됩니다. 또한 동적 형식 저장 및 인스턴스화는 많이 해결되지 않습니다. GetConfigValue () 메소드가 모든 유형을 리턴 할 수있는 경우 런타임시 여전히 평가되어야하는 Object를 리턴해야합니다 (또는 예상 된 유형이 제공되어야 함).
KeithS

5
옵션 1은 내가 본 소프트웨어에서 구현되었으므로 옵션 2로 변환해야했습니다. 옵션 2는 시간이 지남에 따라 유지 관리가 쉬우 며 처음에는 올바르게 구현하는 데 더 많은 시간이 걸립니다. 옵션 1은 빠르고 쉽게 구현할 수 있지만 소프트웨어가 커질 가능성이 적지 않으면 시간이 지남에 따라 유지 관리가 끔찍합니다.
Jimmy Hoffa

8

나를 위해, 당신이 단일 행 또는 EAV를 갈 것인지는 당신이 그들을 소비하려는 방법에 달려 있습니다.

EAV의 장점은 구조를 변경하지 않고도 새로운 데이터를 추가 할 수 있다는 것입니다. 즉, 새 구성 값을 원하는 경우 테이블에 추가하고 코드에서 원하는 위치로 가져와 도메인, 스키마, 매핑, DAL 쿼리에 새 필드를 추가 할 필요가 없습니다. 등

단점은 가장 간결한 구조 만 가지고 있기 때문에 데이터를 비관적으로 처리해야한다는 것입니다. 구성 값을 사용할 때마다 값이 존재하지 않거나 올바른 형식이 아니어야하며 그렇지 않은 경우 적절하게 작동해야합니다. 구성 값은 double, int 또는 char로 구문 분석 할 수 없습니다. null 일 수 있습니다. 값에 대한 행이 전혀 없을 수 있습니다. 이 문제를 해결하는 방법에는 일반적으로 특정 코드 내 유형의 모든 구성 값에 대해 하나의 유효한 "기본"값이 필요합니다 ( 매우 드문 경우입니다. 더 자주 기본값은 코드를 소비하는 데 전혀 문제가되지 않습니다). 하드 코딩 된 기본값의 사전을 유지하십시오 (새 열이 추가 될 때마다 변경되어야하므로 EAV 스토리지의 주요 이점이 무용지물입니다).

하나의 넓은 행은 그 반대입니다. 존재하는 모든 구성 값에 대한 필드 / 프로퍼티가있는 Configuration 오브젝트의 단일 인스턴스에이를 맵핑합니다. 컴파일 타임에 이러한 값의 유형을 정확히 알고 구성 열이 존재하지 않거나 적절한 유형의 값이없는 경우 DAL에서 "빠르게 실패"하여 예외 기반으로 예외를 포착 할 수 있습니다. 구성 검색 / 수화 문제.

가장 큰 단점은 각각의 새로운 가치에 대해 구조적 변화가 필요하다는 것입니다. 새 DB 열, DAL의 새 열 (매핑 또는 SQL 쿼리 / SP), 새 도메인 열, 모두 사용을 올바르게 테스트하는 데 필요합니다.

이들 중 하나를 사용하는 적절한 상황은 단점이 완화되는 상황입니다. 나를 위해 대부분의 구성 코딩 상황은 단일 행 구현을 요구했습니다. 이는 주로 프로그램의 일부 동작을 제어하는 ​​완전히 새로운 구성 값을 도입하는 경우 새 구성 값을 사용 하도록 코드를 변경해야하기 때문입니다 . 왜 설정 객체로 튀어 나와서 사용할 값을 추가하지 않습니까?

즉, 구성을 저장하기위한 EAV 스키마는 실제로 해결해야하는 문제를 해결하지 못하며 문제에 대한 대부분의 해결 방법은 DRY를 위반합니다.


3

특히 구성 값의 경우 단일 행으로 이동하십시오. 현재 개발을 진행하고 있지 않다면 얼마나 자주 해당 열이 변경됩니까?

대규모 릴리스 사이에서 다운 타임에 발생하지 않는 확장 성을위한 코드보다는 의 데이터 유형을 보호하는 것이 가장 좋습니다 . 또한 단일 열을 추가하거나 제거하는 것이 가장 쉬운 마이그레이션입니다. 새로운 구성 옵션을 만들 때 골치 아프지 않습니다.

또한 "사용자"는 제한을 두지 않고 이러한 옵션을 구성 할 수 있다고 말했습니다. 사용자 별 구성입니까? 그렇다면 구성 옵션이 사용자 당 단일 행인 열에 있어야한다고 강력하게 주장합니다. 나중에 많은 유지 관리 문제를 줄일 수 있습니다.


2

클라이언트가 JSON 프래그먼트 (배열 및 사전뿐만 아니라 일반 문자열, 숫자, 부울, 널값)도 처리 할 수있는 경우 옵션 이름 및 JSON을 포함하는 문자열 값이있는 다중 행 테이블을 가질 수 있습니다. 이를 통해 구조화 된 값을 저장할 수 있으며이를 처리하기위한 코드가 이미 있어야합니다.

클라이언트가 JSON 조각을 처리 할 수 ​​없으면 새 클라이언트를 확보하십시오.


1

단일 행 프로 : 잘 정의되어 있습니다. 단점 : 구성 변경이 어려울 수 있습니다. DB 마이그레이션 등

Entity-Value Pros : 유연성이 뛰어나고 구성 변경을 지원합니다. 단점 : 참조 무결성? 코드에서 더 많은 검사를 수행하여 속성이 존재하는지 확인한 후 속성을 수행하십시오.

Mongo와 같은 비 관계형 DB로 뒷받침되는 접근법 2를 사용합니다. 당신이 확신 할 수있는 것이 있다면, 그 변화입니다.


1

둘 다 사용하십시오!

여러 인스턴스를 가질 수있는 옵션과 일반 옵션을 정렬하십시오.

단일 행 테이블 (구성)

  id  |  company_name  |  start_fullscreen  |  refresh_seconds  |  ...
------+----------------+--------------------+-------------------+-------
  4   |  ACME Inc.     |  true              |  20               |  ...

이름-값 쌍 테이블 (옵션)

  name             |  value          | update_time  
-------------------+-----------------+--------------
  generic_option_1 |  Option 1 Value | timestamp    
  generic_option_2 |  Option 2 Value | timestamp    
  generic_option_3 |  Option 3 Value | timestamp    
  configuration    |  4              | timestamp    
  ...              |  ...            | ...          

나는 이것이 더 유연하다고 생각합니다.

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