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


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.