사용자 정의 필드를 사용하여 사용자 데이터베이스를 설계하는 방법


18

이 질문은 데이터베이스를 어떻게 디자인 해야하는지에 관한 것입니다. 더 나은 솔루션이 무엇인지에 따라 관계형 / nosql 데이터베이스가 될 수 있습니다


"회사"및 "사용자"를 추적하기 위해 데이터베이스를 포함하는 시스템을 작성해야하는 요구 사항이 있습니다. 단일 사용자는 항상 한 회사에만 속합니다

  • 사용자는 한 회사에만 속할 수 있습니다
  • 회사는 많은 사용자를 가질 수 있습니다

"회사"테이블의 디자인은 매우 간단합니다. 회사는 다음과 같은 속성 / 열을 갖습니다. (간단하게 유지합시다)

ID, COMPANY_NAME, CREATED_ON

첫 번째 시나리오

간단하고 간단하게 사용자는 모두 동일한 속성을 가지므로 관계형 스타일의 사용자 테이블로 쉽게 수행 할 수 있습니다.

ID, COMPANY_ID, FIRST_NAME, LAST_NAME, EMAIL, CREATED_ON

두 번째 시나리오

다른 회사가 사용자에 대해 다른 프로필 속성을 저장하려는 경우 어떻게됩니까? 각 회사에는 해당 회사의 모든 사용자에게 적용되는 정의 된 속성 세트가 있습니다.

예를 들면 다음과 같습니다.

  • 회사 A가 저장하려고 함 : LIKE_MOVIE (부울), LIKE_MUSIC (부울)
  • 회사 B가 다음을 저장하려고합니다. FAV_CUISINE (문자열)
  • 회사 C는 다음을 저장하려고합니다. OWN_DOG (부울), DOG_COUNT (int)

접근법 1

무차별 대입 방법은 사용자에 대한 단일 스키마를 보유하고 회사에 속하지 않는 경우 널을 갖도록하는 것입니다.

ID, COMPANY_ID, FIRST_NAME, LAST_NAME, EMAIL, LIKE_MOVIE, LIKE_MUSIC, FAV_CUISINE, OWN_DOG, DOG_COUNT, CREATED_ON

이는 많은 NULLS 및 열과 관련이없는 열이있는 사용자 행으로 끝날 것이기 때문에 다소 불쾌합니다 (예 : 회사 A에 속한 모든 사용자는 FAV_CUISINE, OWN_DOG, DOG_COUNT에 대해 NULL 값을 가짐)

접근법 2

두 번째 방법은 "자유 양식 필드"를 사용하는 것입니다.

ID, COMPANY_ID, FIRST_NAME, LAST_NAME, EMAIL, CUSTOM_1, CUSTOM_2, CUSTOM_3, CREATED_ON

사용자 정의 필드가 무엇인지 모르기 때문에 자체적으로 불쾌 할 수 있습니다. 데이터 유형은 저장된 값을 반영하지 않습니다 (예 : int 값을 VARCHAR로 저장합니다).

접근법 3

PostgreSQL JSON 필드를 살펴 보았습니다.이 경우 다음을 갖게됩니다.

ID, COMPANY_ID, FIRST_NAME, LAST_NAME, EMAIL, CUSTOM_PROFILE_JSON, CREATED_ON

이 경우 어떻게 다른 스키마를 사용자에게 적용 할 수 있습니까? 회사 A의 사용자에게는 다음과 같은 스키마가 있습니다.

 {"LIKE_MOVIE":"boolean", "LIKE_MUSIC": "boolean"}

회사 C의 사용자는 다른 스키마를 가지지 만

 {"OWN_DOG ":"boolean", "DOG_COUNT": "int"}

이 문제를 어떻게 해결해야합니까? 관계 (회사)를 기반으로 단일 "개체"(사용자)에 대해이 유연한 스키마를 허용하도록 데이터베이스를 올바르게 설계하려면 어떻게해야합니까?

관계형 솔루션? nosql 솔루션?


편집 : 또한 사용자 속성을 열이 아닌 행에 저장하는 "CUSTOM_PROFILE"테이블에 대해서도 생각했습니다.

이 방법에는 두 가지 문제가 있습니다.

1) 사용자 당 데이터 가 열이 아닌 행으로 증가합니다. 즉 , 사용자에 대한 전체 그림을 얻으려면 많은 조인을 수행해야하며 서로 다른 사용자 지정 특성의 "사용자 지정 프로필"테이블에 여러 번 조인해야합니다.

2) 데이터 값이 정수 또는 부울 등으로 알고 있음에도 불구하고 데이터 값은 항상 VARCHAR로 저장되어 일반적입니다.


3
회사마다 고객마다 서로 다른 다중 값 데이터 세트가있는 경우 COMPANY_CUSTOMER 연결 테이블이 필요합니다. 다른 모든 것들은 곧 당신에게 큰 고통을 줄 것입니다.
Kilian Foth

연결 테이블이 사용자 지정 데이터에 어떤 도움이됩니까? 열은 여전히 ​​달라야합니다.
noobcser

1
"회사 : IKEA, CUSTOMER : Kilian, ATTRIBUTE : password, VALUE : kitten"과 같은 튜플을 사용하여 "IKEA의 Kilian 비밀번호가 'kitten'"이라는 사실을 나타내야합니다. 더 간단한 것은 일을하지 않습니다.
Kilian Foth

3
스키마는 정의상 고정 된 것입니다. 필요한 필드가 무엇인지 모르는 경우 설정할 수 없습니다. 이와 같은 문제는 관계형 데이터베이스에서 해결되는 경향이 있는 Entity-Attribute-Value 를 살펴보십시오 .
메이슨 휠러

답변:


13

이것을 대안으로 고려하십시오. 앞의 두 예제는 모두 "custom_column"솔루션을 확장하고 유지하기가 어려우면서 응용 프로그램의 범위가 커짐에 따라 스키마를 변경해야합니다. 결국 Custom_510으로 끝나고이 테이블이 얼마나 끔찍한 지 상상해보십시오.

먼저 회사 스키마를 사용하십시오.

[Companies] ComnpanyId, COMPANY_NAME, CREATED_ON

다음으로 모든 회사에서 사용 / 공유 할 최상위 필수 속성에 사용자 스키마를 사용합니다.

[Users] UserId, COMPANY_ID, FIRST_NAME, LAST_NAME, EMAIL, CREATED_ON

다음으로 각 회사의 사용자 정의 사용자 속성에 고유 한 동적 속성을 정의 할 테이블을 작성합니다. 따라서 속성 열의 예제 값은 "LikeMusic"입니다.

[UserAttributeDefinition] UserAttributeDefinitionId, CompanyId, Attribute

다음으로 사용자 속성 값을 보유 할 UserAttributes 테이블을 정의합니다.

[UserAttributes] UserAttributeDefinitionId, UserId, Value

성능을 향상시키기 위해 여러 가지 방법으로 수정할 수 있습니다. UserAttributes에 여러 테이블을 사용하여 각각 Value에 저장되는 데이터 유형에 고유하게 만들거나 VarChar로 그대로두고 키값 저장소로 작업 할 수 있습니다.

나중에 교정 할 수 있도록 CompanyId를 UserAttributeDefiniton 테이블에서 상호 참조 테이블로 이동할 수도 있습니다.


고마워-나는 그런 접근법에 대해-편집을 참조하십시오. 2 문제 : 1) 데이터가 행으로 커지므로 사용자를 완전히 파악하려면 많은 조인을 수행해야합니다. 2) 값이 실제로 int 또는 boolean
등인

1
테이블 ID에 int / bigint를 사용하고 이들을 조인하면 행 수가 극단이 될 때까지 성능 문제가 발생하지 않습니다. 이제 속성 값을 기준으로 검색을 시작하면 많은 수의 레코드를 얻기 시작하면 문제가 발생할 수 있습니다. 이 경우 DBA와 협력하여 생성 가능한 인덱스 또는 이러한 종류의 검색 속도를 높일 수있는 인덱싱 된 뷰가 있는지 확인했습니다. 비슷한 스키마를 사용했으며 성능 문제가없는 해마다 1 억 건의 레코드를 사용하므로 기본 디자인이 제대로 작동합니다. IMO
P. Roe

보고, 필터링, 쿼리가 필요하고 다른 속성이 다른 데이터 세트에 속할 수 있습니다. 이 접근법이 NoSQL보다 낫습니까? 성능 차이를 이해하려고합니다. 비슷한 상황의 사용자 만 사용자 정의 필드가 포함 된 보고서를 정의 할 수 있습니다.
kos

위의 접근 방식에서 diff로 검색 항목을 어떻게 구현합니까? 회사는 사용자 필드를 포함하여 해당 필드를 검색하려고합니다. 확장 가능한 검색을 제공하는 올바른 접근 방법은 무엇입니까?
techagrammer

일반적으로 많은 조인으로 검색 할 수 있습니다. ETL 스크립트를 사용하여 검색하려는 데이터를 추출하여보다 비정규 화 된 구조에 배치 할 수 있습니다. 마지막으로 검색 방법으로 인덱싱 된 뷰를 사용할 수 있습니다. 개인적으로 검색하기 쉬운 비정규 화 된 구조를 생성하기 위해 ETL 방법을 권장합니다.
P. Roe

7

NoSQL 데이터베이스를 사용하십시오. 회사 및 사용자 문서가있을 것입니다. 사용자는 사용자 템플릿 (해당 회사의 필드 / 유형을 나타내는 텍스트)을 기반으로 스키마의 일부를 동적으로 만들게됩니다.

\Company\<uniqueidentifier>
    - Name: <Name>
    - CreatedOn: <datetime>
    - UserTemplate: <Text>

\User\<uniqueidentifier>
    - COMPANY_ID: <ID>
    - FIRST_NAME: <Text>
    - LAST_NAME: <Text>
    - EMAIL: <Text>
    - CREATED_ON: <datetime>
    - * Dynamically created fields per company

이것이 Firebase.com 과 같은 방식으로 보일 수있는 방법입니다. 어떤 방법 으로든 어떻게해야하는지 배워야합니다.


이것이 내가 생각하거나 JSON 열에 대한 것입니다. PRoe에서 제안한 솔루션과 비교하여 쿼리, 필터링보고에 대한 성능은 어떻습니까?
kos

1
데이터를 json 또는 xml로 압축 한 다음 열에 던져 넣으면 검색 속도가 매우 느려집니다. 위의 답변에 제시 된 데이터를 검색 해야하는 경우 인덱싱 된 뷰를 사용하여 데이터를 검색하는 것이 좋습니다. 해당 솔루션이 이상적이지 않으면 ETL을 사용하여 쉽게 검색하고보고 할 수있는 구조로 데이터를 복사하는 것이 좋습니다.
P. Roe

위의 접근 방식에서 diff로 검색 항목을 어떻게 구현합니까? 회사는 사용자 필드를 포함하여 해당 필드를 검색하려고합니다. 확장 가능한 검색을 제공하는 올바른 접근 방법은 무엇입니까?
techagrammer

nosql 데이터베이스에는 중복 데이터가있을 수 있지만 검색 가능한 방식으로 구성됩니다. 위에 표시된 것은 고유 식별자입니다. 다른 하나는 \ Company \ Name 일 수 있습니다. 여러 인덱스를 갖는 것과 비슷합니다.
JeffO

3

사용자 정의 필드 요청을 자주 수행하는 경우 실제로 데이터베이스와 비슷한 방식으로 모델링합니다. 각 사용자 정의 필드, CompanyCustomField (데이터가 속한 사용자, 데이터 유형 등)에 대한 메타 데이터와 CustomerId, FieldId 및 값을 포함하는 다른 테이블 CompanyCustomFieldValues를 보유하는 테이블을 작성하십시오. Microsoft Sql Server와 같은 것을 사용하는 경우 값 열이 sql_variant 데이터 유형이됩니다.

물론 관리자가 각 고객에 대한 사용자 정의 필드를 정의 할 수있는 인터페이스와 실제로이 메타 데이터를 사용하여 필드 값을 수집하기위한 UI를 작성하는 다른 인터페이스가 필요하므로 이는 쉽지 않습니다. 필드 그룹화와 같은 다른 요구 사항이 있거나 선택 목록 종류의 필드를 수행해야하는 경우 더 많은 메타 데이터 / 다른 테이블 (예 : CompanyCustomFieldPickListOptions)을 추가해야합니다.

이것은 사소한 것이 아니지만 모든 새로운 사용자 정의 필드에 대해 데이터베이스 변경 / 코드 변경이 필요 없다는 장점이 있습니다. 사용자 정의 필드의 다른 모든 기능도 코딩해야합니다 (예 : 문자열 값을 정규식으로 검증하거나 특정 범위 사이의 날짜 만 허용하려는 경우 또는 다른 사용자 정의 필드 값을 기반으로 한 사용자 정의 필드를 활성화해야하는 경우) ).


고마워-나는 그런 접근법에 대해-편집을 참조하십시오. 2 문제 : 1) 데이터가 행으로 커지므로 사용자를 완전히 파악하려면 많은 조인을 수행해야합니다. 2) 값이 실제로 int 또는 boolean
등인

1
@noobcser 모든 데이터베이스가 행과 조인을 중심으로 설계 한 후에 행으로 증가하는 데이터는 실제로 중요하지 않습니다. 어쨌든 이런 종류의 일에 상당히 유용한 공통 테이블 표현식을 사용할 가능성이 큽니다. sql_variant를 값 열의 데이터 유형으로 사용할 수 있다고 말한 부분을 놓쳤는 지 확실하지 않습니다. MS SQL Server 기능 이름의 이름을 지정하는 동안 다른 성숙한 DBMS에도 비슷한 기능이있을 것으로 기대합니다.
Andy

1
@noobcser 참고로 나는 실제로 내 경력에서 이러한 요구 사항을 매우 자주 경험하고 제안 된 각 솔루션에 대한 경험이 있으므로 내 경험에서 가장 효과가 좋은 것을 제안합니다. 이런 종류의 일에 xml 데이터 형식을 사용하는 것은 MS가 xml을 기본 데이터 형식으로 추가하는 것을 싫어하는 이유입니다.
Andy

1

다른 답변에 대한 대안은 profile_attrib라는 테이블을 갖거나 스키마가 응용 프로그램에서 완전히 관리하는 것과 비슷합니다.

사용자 지정 속성이 추가되면 속성 ALTER TABLE profile_attrib ADD COLUMN like_movie TINYINT(1)삭제가 금지 될 수 있습니다. 이는 유연성을 제공하면서도 참여를 최소화합니다.

비트 트레이드 오프는 이제 응용 프로그램이 데이터베이스에 대한 테이블 권한을 변경해야하며 열 이름을 삭제하는 것에 대해 똑똑해야한다고 생각합니다.


정규 표현식 [^\w-]+은 잘 처리해야하며 그렇지 않은 것은 허용하지 않습니다. 0-9A-Za-z_-그러나 예를 들어, 살균은 악의 또는 어리 석음으로부터 보호해야합니다.
Regular Joe

0

귀하의 질문에는 많은 잠재적 인 해결책이 있습니다. 한 가지 해결책은 추가 속성을 XML로 저장하는 것입니다. XML은 텍스트로 저장되거나 XML 형식을 XML (SQL Server)로 지원하는 데이터베이스를 사용하는 경우 저장할 수 있습니다. 텍스트로 저장하면 쿼리 기능 (예 : 사용자 정의 속성 검색)이 제한되지만 저장 및 검색이 모두 필요한 경우 좋은 솔루션입니다. 쿼리해야하는 경우 XML을 XML 유형으로 저장하는 것이 더 나은 옵션입니다 (공급 업체별로 다르지만).

이를 통해 고객 테이블에 추가 열을 추가하여 고객에게 원하는 수의 속성을 저장할 수 있습니다. 하나는 속성을 해시 셋이나 딕셔너리로 ​​저장할 수 있습니다. 모든 것이 시작하는 문자열이기 때문에 타입 안전이 손실되지만 날짜, 숫자, 부울에 표준 형식 문자열을 적용하면 정상적으로 작동합니다.

자세한 내용은:

https://msdn.microsoft.com/en-us/library/hh403385.aspx

@WalterMitty의 대답은 유효하지만 다른 속성을 가진 고객이 많은 경우 상속 모델을 따르는 경우 많은 테이블이 생길 수 있습니다. 고객간에 공유되는 사용자 지정 속성 수에 따라 다릅니다.


이것은 잘 작동 할 수 있지만 XML / JSON 필드에 저장된 데이터에 대해 실제로 무언가를 해야하는 경우 제한적이라고 생각합니다.
Andy

@Andy-사실, 다른 레이어가 있습니다. 쿼리 DB와 달리 DB를 쿼리하고 XML을 구문 분석합니다. 나는 그것을 제한이라고 부를 지 모르겠지만, 더 성가시다. 그러나 사용자 정의 속성이 광범위하게 사용된다면 고려해야 할 사항입니다.
Jon Raynor

T-SQL에서는 네임 스페이스에 대해 XML / JSON 열의 내용을 정의하고 사용자 지정 데이터의 요소에 대해 쿼리 할 수 ​​있습니다. 어렵지 않습니다
Stephen York

-1

각기 다른 유형의 회사 프로필마다 3 개의 서로 다른 테이블이 있도록 데이터베이스를 정규화해야합니다. 예제를 사용하면 열이있는 테이블이 있습니다.

USER_ID, LIKE_MOVIE, LIKE_MUSIC

USER_ID, FAVORITE_CUISINE

USER_ID, OWN_DOG, DOG_COUNT

이 접근법은 회사가 사전에 저장하고자하는 정보의 형태를 알고 있으며 자주 변경되지 않는다고 가정합니다. 디자인 타임에 데이터의 모양을 알 수없는 경우 해당 JSON 필드 또는 nosql 데이터베이스를 사용하는 것이 좋습니다.


-1

어떤 이유로 든 데이터베이스는 내부 플랫폼 효과가 가장 자주 나타나는 필드입니다. 이것은 안티 패턴 팝업의 또 다른 경우입니다.

이 경우 자연스럽고 올바른 솔루션과 싸우려고합니다. 회사 A의 사용자는 회사 B의 사용자가 아니며 자신의 필드에 대한 자체 테이블이 있어야합니다.

데이터베이스 공급 업체는 테이블별로 요금을 부과하지 않으며 테이블의 두 배에 대해 디스크 공간이 두 배가 필요하지 않습니다 (실제로 두 사용자가 B의 사용자에 대한 A의 속성을 저장하지 않기 때문에 두 개의 테이블을 사용하는 것이 더 효율적입니다). 공간을 차지합니다).

물론 공통 필드가 충분하면이를 공유 사용자 테이블로 분류하고 각 회사 별 사용자 테이블에 외래 키를 가질 수 있습니다. 이것은 데이터베이스 쿼리 최적화 프로그램이 어려움을 겪지 않는 매우 간단한 구조입니다. 필요한 조인은 간단합니다.


3
그리고 수천 명의 고객이있는 경우 각 고객의 사용자 정의 필드에 대한 사용자 정의 코드가 필요하다는 것은 말할 것도없이 각 테이블 당 테이블을 빠르게 유지 관리 할 수 ​​없게 될 수 있습니다.
Andy

@ 앤디 : 무엇을 추측? 수천 개의 서로 다른 구성표를 단일 테이블에 혼합하면 상황을 훨씬 더 유지할 수 없습니다! 그렇습니다. 아마도 커스텀 필드에 커스텀 코드가 필요할 것입니다. 각 고객이 깨끗하고 별도의 테이블을 가지고 있다면 더 간단하고 어렵지 않습니다. 다른 회사에서 회사 X의 분야를 선택하려고 시도하는 것은 피의 혼란입니다.
MSalters

고객 테이블에 모든 추가 열을 처리하는 내 대답이나 OP 아이디어를 언급하고 있습니까?
Andy

2
여기서 목표는 유지 관리 가능하고 확장 가능한 솔루션을 찾는 것입니다. 고객 당 테이블을 만드는 것은 분명히 반대입니다. 새 고객을 온보드 할 때마다 테이블 작성 스크립트를 실행하고 코드 (Entity 오브젝트)를 업데이트 한 후 다시 배치하는 것은 현실적이지 않습니다.
tsOverflow

모든 고객에 대해 공유 테이블을 사용한다는이 아이디어는 그 자체가 별도의 SaaS 아키텍처 토론이므로 고객을 다른 테이블 (또는 다른 데이터베이스에 두어 고객별로 백업 / 복원 및 확장 가능)로 유지해야하는 몇 가지 이유가 있습니다. 이 시나리오에서 기본 테이블에 cusotm 컬럼을 작성하는 것은 쉬운 일이 아닙니다. 나는 공감했고, 사람들이 왜이 접근법을 좋아하지 않기 때문에 이것을 공감하는지 궁금합니다. 내부 플랫폼 효과는 현실입니다. EVA 모델을 사용하면 쿼리가 더 어려워지고, 더 세게, 무결성이 어려워집니다.
drizin

-1

내 솔루션은 프로그램 에서이 쿼리를 호출한다고 가정하고 사후 처리를 수행 할 수 있어야합니다. 다음과 같은 열을 가질 수 있습니다.

ID, COMPANY_ID, FIRST_NAME, LAST_NAME, EMAIL, CUSTOM_VALUES

CUSTOM_VALUES는 키와 값 쌍을 저장하는 문자열 유형입니다. 키는 열 이름이고 값은 열 값입니다. 예 :

LIKE_MOVIE;yes;LIKE_MUSIC;no;FAV_CUISINE;rice

이 CUSTOM_VALUES에는 존재하는 정보 만 저장합니다. 프로그램에서 쿼리 할 때이 문자열을 분할하여 사용할 수 있습니다.

나는이 논리를 사용하고 있으며 잘 작동합니다. 조회가 아닌 코드에 필터링 논리를 적용해야한다는 것입니다.

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