SQL Server 데이터베이스에서 단일 행 구성 테이블 사용 나쁜 생각?


145

쇼핑 카트 응용 프로그램을 개발할 때 관리자의 기본 설정 및 요구 사항에 따라 설정 및 구성을 저장해야한다는 것을 알았습니다. 이 정보는 회사 정보, 배송 계정 ID, PayPal API 키, 알림 환경 설정 등 모든 것이 될 수 있습니다.

관계형 데이터베이스 시스템에 단일 행을 저장하기 위해 테이블을 작성하는 것은 매우 부적절한 것 같습니다.

이 정보를 저장하는 적절한 방법은 무엇입니까?

참고 : 내 DBMS는 SQL Server 2008이며 프로그래밍 계층은 ASP.NET (C #)으로 구현됩니다.

답변:


189

과거에는 단일 행 테이블과 키 / 값 쌍 테이블의 두 가지 방법을 수행했으며 각 접근 방식에는 긍정적이고 부정적인 것이 있습니다.

단일 행

  • 양수 : 값이 올바른 유형으로 저장됩니다
  • 긍정적 : 코드로 다루기가 더 쉽습니다 (위로 인해)
  • 양수 : 기본값은 각 설정에 개별적으로 제공 될 수 있습니다
  • 부정 : 새 설정을 추가하려면 스키마를 변경해야합니다.
  • 음수 : 설정이 많으면 테이블이 매우 넓어 질 수 있습니다.

키 / 값 쌍

  • 긍정적 : 새로운 설정을 추가 할 때 스키마를 변경할 필요가 없습니다.
  • 양수 : 테이블 스키마가 좁고 새로운 설정에 추가 행이 사용됩니다.
  • 음수 : 각 설정의 기본값이 동일합니다 (널 / 빈?).
  • 음수 : 모든 것이 문자열로 저장되어야합니다 (예 : nvarchar)
  • 부정적 : 코드에서 설정을 처리 할 때 설정 유형을 알고 전송해야합니다.

단일 행 옵션은 작업하기 가장 쉬운 옵션입니다. 이는 각 설정을 데이터베이스에 올바른 유형으로 저장할 수 있고 설정 유형과 조회 키를 코드에 저장할 필요가 없기 때문입니다.

이 접근 방식을 사용하는 데 관심이있는 한 가지는 "특별한"단일 행 설정 테이블에 여러 행이있는 것이 었습니다. 나는 이것을 SQL Server에서 극복했다.

  • 기본값이 0 인 새 비트 열 추가
  • 이 열의 값이 0인지 확인하기위한 점검 제한 조건 작성
  • 비트 열에 고유 제한 조건 작성

이는 비트 열의 값이 0이므로 테이블에 하나의 행만 존재할 수 있지만 고유 제한 조건으로 인해 해당 값을 가진 행이 하나만있을 수 있음을 의미합니다.


5
우리는 LOB 응용 프로그램에서 단일 행 작업을 수행합니다. 값은 모두 올바른 유형이므로 응용 프로그램에서 값을 사용하는 것이 훨씬 간단합니다. 스키마는 응용 프로그램과 함께 버전이 지정되므로 구성 설정 변경은 응용 프로그램 개정과 마찬가지로 관리됩니다.
DaveE

17
단일 행 양수 : 일부 열에 FK를 정의 할 수 있습니다!
wqw

8
유형 식별자로 키 / 값 쌍을 수행하여 값 유형에 값이있는 열을 결정할 수 있습니다. 이를 통해 두 가지 이점을 모두 누릴 수 있으며 저장된 proc를 사용하여 필요할 때 가치를 얻을 수 있습니다.
Middletone

19
실제로 단일 행 솔루션을 구현 한 후 하루를 망칠 수있는 한 것은 나중에 임무를하는 경우 "의는 각 값이 변경되었습니다 누가 .... 그것을 마지막으로 변경된 시간을 추적하자"입니다
데이브 Mateer

6
한 가지 사례에서 발견 한 단일 행 솔루션의 또 다른 장점 : "설정"에 대한 단일 행 테이블을 사용하여 한 클라이언트 용으로 빌드 된 응용 프로그램이 있습니다. 나중에 동일한 응용 프로그램을 사용하고 싶지만 다른 설정을 원했던 두 명의 다른 클라이언트를 확보했습니다. 각 클라이언트에 대해 별도의 설정 세트를 유지하기 위해 "client_id"PK를 테이블에 추가하기 만하면됩니다. (이것은 이러한 "설정"이 실제로 모델링하지 않은 상위 ​​수준 엔터티에 대한 속성이라는 것을 깨달을 때입니다.)
Jeffrey Kemp

10

정보 유형 및 정보 값에 대한 열이있는 테이블을 작성해야합니다 (적어도). 이렇게하면 새 정보가 추가 될 때마다 새 열을 만들지 않아도됩니다.


1
간단하고 깔끔합니다. 거기에서 주요 값 쌍 목록으로 작업하십시오. 당신은 기본이 조금 값에 대해 생각 할 수 있습니다 ... 사용의 맥락에 따라 달라집니다
폴 콜러

4
새 열을 만드는 것이 왜 문제입니까? SQL 스키마 업데이트와 관련된 정치적 문제로 인해 개발자가 피해야하는 상황이 있지만 문제에 대해서는 언급하지 않았습니다.
finnw

6

단일 행이 정상적으로 작동합니다. 그것은 강한 유형을 가질 것입니다 :

show_borders    bit
admin_name      varchar(50)
max_users       int

한 가지 단점은 alter table새 설정을 추가하기 위해 스키마 변경 ( )이 필요하다는 것입니다 . 한 가지 대안은 다음과 같은 테이블로 끝나는 정규화입니다.

pref_name       varchar(50) primary key
pref_value      varchar(50) 

이것은 약한 유형을 가지고 있지만 (모든 것이 varchar입니다) 새로운 설정을 추가하는 것은 단지 행을 추가하는 것입니다. 데이터베이스 쓰기 액세스로 할 수있는 일입니다.


4

개인적으로, 그것이 효과적이라면 단일 행에 저장합니다. SQL 테이블에 저장하기 위해 과잉? 아마도, 그러나 그렇게 할 때 실질적인 피해는 없습니다.


4

가장 간단한 상황을 제외하고 모든 구성 매개 변수를 단일 행에 배치하면 많은 단점이 있습니다. 나쁜 생각입니다 ...

구성 및 / 또는 사용자 기본 설정 유형의 정보를 저장하는 편리한 방법은 XML 입니다. 많은 DBMS가 XML 데이터 형식을 지원합니다. XML 구문을 사용하면이 구성이 발전함에 따라 구성을 설명하는 "언어"및 구조를 사용할 수 있습니다. XML의 장점 중 하나는 계층 구조를 암시 적으로 지원한다는 것입니다. 예를 들어 번호가 붙은 접미사로 이름을 지정하지 않고도 작은 구성 매개 변수 목록을 저장할 수 있습니다. XML 형식의 가능한 단점은이 데이터를 검색하고 일반적으로 수정하는 것이 다른 접근 방식만큼 간단하지 않다는 것입니다 (복잡하지는 않지만 단순 / 자연적인 것은 아님).

관계형 모델에 더 가깝게 유지 하려면 Entity-Attribute-Value 모델 이 필요할 것입니다. 개별 값은 일반적으로 다음과 같은 테이블에 저장됩니다.

EntityId     (foreign key to the "owner" of this attribute)
AttributeId  (foreign key to the "metadata" table where the attribute is defined)
StringValue  (it is often convenient to have different columns of different types
IntValue      allowing to store the various attributes in a format that befits 
              them)

여기서 AttributeId는 가능한 각 속성 (귀하의 경우 "구성 매개 변수")이 정의 된 테이블에 대한 외래 키입니다.

AttributeId  (Primary Key)
Name
AttributeType     (some code  S = string, I = Int etc.)
Required          (some boolean indicating that this is required)
Some_other_fields   (for example to define in which order these attributes get displayed etc...)

마지막으로 EntityId를 사용하면 이러한 다양한 속성을 "소유"하는 일부 엔티티를 식별 할 수 있습니다. 귀하의 경우 UserId이거나 관리 할 구성이 하나 뿐인 경우에도 암시적일 수 있습니다.

EAV 모델은 응용 프로그램이 발전함에 따라 가능한 구성 매개 변수 목록이 커지도록하는 것 외에도 "메타 데이터", 즉 속성 자체와 관련된 데이터를 데이터 테이블에 배치하므로 일반적으로 보이는 열 이름의 모든 하드 코딩을 피합니다 구성 매개 변수가 단일 행에 저장된 경우


3
대부분의 구성 테이블 사용에있어 과도한 것으로 보입니다.
JerryOL

이 접근법의 기본 개념은 훌륭하다고 생각합니다. 그러나 왜 XML인가? JSON 또는 YAML과 같은 간단한 데이터 교환 형식을 선택하면 다른 변형에서 이점을 얻을 수 있습니다.
schlamar

1
EAV는 관계형이지만 정규화되지 않았습니다. 확실히 사용 사례가 있지만 (예 : ORM 시스템은 메타 데이터가 EAV 용 데이터베이스에 있다는 주장이 설득력있는 이유는 아닙니다. 모든 RDBMS에는 시스템 테이블에 메타 데이터가 포함되어 있으므로 검색 할 수 있으므로 단일 행 테이블에도 데이터베이스에 메타 데이터가 있습니다. 하드 코딩 된 열 이름도 문제가되지 않습니다. 엔터티 및 특성에 키를 사용하는 경우이를 정의하는 다른 위치에 하드 코딩 된 룩업 테이블이 있습니다 (또는 프레젠테이션 레이어에 더 나쁩니다).
다 보스

3

정규화 된 접근 방식에서 새 구성 매개 변수를 추가 할 때 스키마를 변경할 필요는 없지만 새 값을 처리하기 위해 코드를 변경하는 중일 수 있습니다.

배포에 "대체 테이블"을 추가하는 것이 단일 행 접근 방식의 단순성 및 유형 안전성에 대한 큰 절충안처럼 보이지는 않습니다.


2

키 및 값 쌍은 구성 설정을 저장할 수있는 .Net App.Config와 유사합니다.

따라서 값을 검색하려면 다음을 수행하십시오.

SELECT value FROM configurationTable
WHERE ApplicationGroup = 'myappgroup'
AND keyDescription = 'myKey';

1

이를 수행하는 일반적인 방법은 "properties"테이블을 특성 파일과 유사하게 만드는 것입니다. 여기에 모든 앱 상수를 저장하거나 너무 일정하지 않은 것을 저장할 수 있습니다.

그런 다음 필요에 따라이 테이블에서 정보를 가져올 수 있습니다. 마찬가지로 저장할 다른 설정이 있으면 추가 할 수 있습니다. 다음은 예입니다.

property_entry_table

[id, scope, refId, propertyName, propertyValue, propertyType] 
1, 0, 1, "COMPANY_INFO", "Acme Tools", "ADMIN"  
2, 0, 1, "SHIPPING_ID", "12333484", "ADMIN"  
3, 0, 1, "PAYPAL_KEY", "2143123412341", "ADMIN"   
4, 0, 1, "PAYPAL_KEY", "123412341234123", "ADMIN"  
5, 0, 1, "NOTIF_PREF", "ON", "ADMIN"  
6, 0, 2, "NOTIF_PREF", "OFF", "ADMIN"   

이 방법으로 보유하고있는 데이터와 내년에 보유하고 아직 모르는 데이터를 저장할 수 있습니다. :).

이 예에서 범위와 refId는 백엔드에서 원하는대로 사용할 수 있습니다. 따라서 propertyType "ADMIN"의 범위가 0 refId 2이면 기본 설정이 무엇인지 알 수 있습니다.

언젠가 관리자가 아닌 정보도 여기에 저장해야 할 때 속성 유형이 제공됩니다.

카트 데이터를 이런 식으로 저장하거나 해당 사항을 조회해서는 안됩니다. 그러나 데이터가 시스템에 특정한 경우이 방법을 사용할 수 있습니다.

예를 들어 : DATABASE_VERSION 을 저장 하려면 다음과 같은 테이블을 사용하십시오. 이렇게하면 앱을 업그레이드해야 할 때 속성 테이블을 확인하여 클라이언트의 소프트웨어 버전을 확인할 수 있습니다.

요점은 장바구니와 관련된 것들에 이것을 사용하고 싶지 않다는 것입니다. 잘 정의 된 관계형 테이블에서 비즈니스 로직을 유지하십시오. 특성 테이블은 시스템 정보 전용입니다.


@finnw이 방법은 특히 다양한 유형의 조회가있는 경우 조회에 사용해서는 안된다는 데 전적으로 동의합니다. 아마도 나는 그 질문을 오해했을 것입니다. 상수 및 시스템 속성에 대한 테이블이 필요한 것처럼 들렸습니다. 이 경우 왜 10 개의 다른 테이블이 있습니까?
Stephano

참고 : "관계형 카트 데이터를 저장해야합니다"가 아니라 "설정 및 구성 저장"이라고
말함

이에 대한 반대 의견은 새로운 속성을 추가 할 때 SQL 스키마 업데이트를 피하기 위해 SQL의 타이핑 및 기타 제약 조건 메커니즘을 무시한다는 것입니다. "내년에있을 데이터에 대해 아직 알지 못하는 데이터" 예, 내년에 새로운 데이터가 생길 것입니다. 그러나 추가 될 때 새로운 (유형화 된) SQL 열, CHECK 및 FOREIGN KEY 제약 조건을 만드는 것을 중단해야 할 것은 무엇입니까?
finnw

나의 첫 번째 본능은 단순히이 데이터를 플랫 파일에 추가하는 것입니다. 그리고 테이블을 사용하는이 프로세스는 실제로 DBMS의 제약 조건 메커니즘을 우회합니다. 그러나 적절한 데이터베이스 기술을 따르기 위해 너무 열심히 노력하면 요점이 없습니다. 첫 번째 답변을 확인하십시오. SO에서 가장 높은 투표 : stackoverflow.com/questions/406760/…
Stephano

2
키 값 쌍을 사용하여 시작시 정렬 된 모든 사전에 덤프합니다.
Paul Creasey

0

단일 행이 구성에 가장 적합한 구현인지 확실하지 않습니다. 두 개의 열 (configName, configValue)이있는 구성 항목 당 행을 갖는 것이 더 나을 수 있지만, 모든 값을 문자열로 캐스팅하고 다시 캐스팅해야합니다.

그럼에도 불구하고 전역 구성에 단일 행을 사용하는 데 아무런 해가 없습니다. DB (글로벌 변수)에 저장하는 다른 옵션이 더 나쁩니다. 첫 번째 구성 행을 삽입 한 다음 테이블에서 삽입을 사용 안함으로 설정하여 여러 행을 방지하여 제어 할 수 있습니다.


0

각 주요 유형에 대한 열과 데이터가있는 열을 알려주는 하나의 열을 추가하여 변환없이 키 / 값 쌍을 수행 할 수 있습니다.

따라서 테이블은 다음과 같습니다.

id, column_num, property_name, intValue, floatValue, charValue, dateValue
1, 1, weeks, 51, , ,
2, 2, pi, , 3.14159, , 
3, 4, FiscYearEnd, , , , 1/31/2015
4, 3, CompanyName, , , ACME, 

약간 더 많은 공간을 사용하지만 최대 수십 개의 속성을 사용합니다. column_num 값에서 case 문을 사용하여 올바른 필드를 가져 오거나 결합 할 수 있습니다.


0

나중에 와서 죄송합니다. 어쨌든, 내가하는 일은 간단하고 효과적입니다. 간단히 세 개의 열이있는 테이블을 만듭니다.

ID-정수 (11)

이름-varchar (64)

값-텍스트

새 구성 열을 작성하거나 업데이트하거나 읽기 전에 수행하는 작업은 "값"을 직렬화하는 것입니다! 이렇게하면 유형이 확실합니다 (글쎄, PHP는 :))

예를 들어 :

b : 0; 위한 B OOLEAN ( 거짓 )

b : 1; 위한 B OOLEAN ( )

i : 1988; 나는 NT를 위해

s : 5 : "카더"; 5 자 길이 의 S TRING 용

이게 도움이 되길 바란다 :)


1
유형에 대한 새 열을 작성하지 않는 이유는 무엇입니까? i:1988두 개의 정보를 하나의 열로 축소하려는 것 같습니다.
maksymiuk

@maksymiuk 간단하게 직렬화를 해제하면 이후의 루프를 사용하는 대신 정확한 유형을 얻을 수 있기 때문에 ... etc
Kader Bouyakoub

루프 나 스위치 등이 필요하지 않은 경우 실제로 각 행에서 정보를 구문 분석해야하는 단계를 제거하는 반면, 유형에 대한 추가 열이있는 경우 정보를 가져 오는 구성 요소에서 유형 정보를 이미 사용할 수 있습니다. 단지 초기 쿼리보다 더 단계를 수행하지 않고
maksymiuk

echo (int) $var정수와 다른 유형에 대해 다른 것을 수행한다는 의미 입니까?
Kader Bouyakoub

0

varchar로 키 열을, JSON으로 값 열을 갖습니다. 1숫자이지만 "1"문자열입니다. true그리고 false모두 부울입니다. 객체도 가질 수 있습니다.

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