사용자 정의 필드를 허용하는 것은 나쁜 습관입니까?


17

일반적으로, 웹 응용 프로그램의 데이터베이스에서 사용자가 만든 필드를 허용하는 것은 나쁜 습관으로 간주됩니까?

예를 들어, 아내를 위해 홈 인벤토리 웹앱을 만들고 있는데, 그녀는 다른 항목에 대해 자신의 필드를 정의하려고합니다. 나는 그녀가 아이템 카테고리를 만들고 그 카테고리에 "기능"을 추가 할 수 있도록 계획하고있었습니다. 기능은 문자열로 저장된 키 / 값입니다. 예를 들어 "오디오 CD"라는 카테고리가있는 경우 "아티스트", "트랙"등의 기능을 추가 할 수 있지만 "가구"와 같은 다른 카테고리에서는 "소재"와 같은 기능을 추가 할 수 있습니다. "(나무, 플라스틱 등). 그런 다음 모든 항목이 하나 이상의 범주에 속하여 해당 기능을 항목에 추가 할 수 있습니다.

이러한 기능을 검색 할 때 문자열 비교가 필요하고 데이터의 유효성 검사 등이 필요하지 않은 문제를 볼 수 있습니다. 민첩한 방법론에 따라 새로운 카테고리와 속성을 제시하는 것이 좋으며 새로운 테이블을 만들어야 할 수도 있습니다. 우리가 간다. 내 예에서는 작은 사용자 기반 (우리 중 2 명)이며 생성 된 레코드의 양이 적으므로 그렇게 나쁘지 않습니다.

그러나 일반적으로 사람들은 "실제"에서 이와 같은 것을 어떻게 처리합니까?


4
MongoDB와 같은 문서 지향 데이터베이스 사용을 고려 했습니까? 유형별로 문서를 저장할 수 있으며 스키마 로 작동하여 편집 할 수도 있습니다 (작은 규모의 프로젝트에서 수동으로).
Andy Hunt

@AndyBursh 현재 postgres가있는 'fun'비트 중 하나는 'json'데이터 유형 ( link )입니다. 이러한 접근 방식을 사용하면 사용자 지정 필드를 해당 데이터, 문서, 문서 등에 저장하고 나머지 필드를 사용하여 적절한 색인 등을 수행 할 수 있습니다. 이 모든 것이 사용법에 달려 있지만 특정 응용 프로그램에 잘 작동하는지 여부를 말하기는 어렵습니다. 그러나 알고 있어야 할 것이 있습니다.

모두 : 훌륭한 토론, 모든 통찰에 감사드립니다! @AndyBursh MongoDB에 대해 들어 보았지만 실제로 읽지 않았습니다. 실험 할 다른 가정 프로젝트처럼 들리지만
zako42

답변:


19

버그 추적기, 고객 리소스 관리 및 이와 유사한 비즈니스 도구에서 흔히 볼 수있는 "사용자 정의 필드"에 도달하기 시작하면 bajillion 필드가있는 테이블로 백업되지 않는다는 것입니다. 자체).

대신 엔티티 속성 값 테이블 디자인과 유효한 속성을 관리하기위한 관련 관리 도구가 있습니다.

다음 표를 고려하십시오.

  + -------------- +
  | 일 |
  | -------------- |
  | 아이디 |
  | 타입 |
  | 디스크 |
  | attr1 |
  | attr2 |
  | attr3 |
  | attr4 |
  | attr5 |
  + -------------- +

이것은 몇 가지 속성을 추가 한 후입니다. 대신 attr1그것을 읽는 척 artist또는 tracks또는 genre또는 것은이 속성 뭐든간에. 그리고 5 대신에 50 대라면 어떨까요. 분명히 관리 할 수 ​​없습니다. 또한 새 필드를 처리하려면 모델을 업데이트하고 응용 프로그램을 재배치해야합니다. 이상적이지 않습니다.

이제 다음 테이블 구조를 고려하십시오.

  + -------------- + + --------------- ++ ------------- +
  | 일 | | thing_attr | | attr |
  | -------------- | | --------------- | | ------------- |
  | id | <--- + | thing_id (fk) | +> | 아이디 |
  | 타입 | | attr_id (fk) | +-+ | 이름 |
  | 디스크 | | 가치 | | |
  + -------------- + + --------------- ++ ------------- +

기본 필드를 가지고 있습니다. 두 개의 테이블이 더 있습니다. 속성이있는 것 각 필드는 attr테이블 의 행입니다 . 그리고 테이블과 테이블과 thing_attr관련된 외래 키 쌍이 있습니다. 그리고 여기에는 해당 엔터티에 대한 필드 값이 무엇이든 저장할 수있는 값 필드가 있습니다.thingattr

이제 attr 테이블을 런타임에 업데이트하고 전체 응용 프로그램에 큰 영향을 미치지 않으면 서 새 필드를 추가하거나 제거 할 수있는 구조가 생겼습니다.

쿼리는 조금 더 복잡하고 유효성 검사도 더욱 복잡해집니다 (펑키 저장 프로 시저 또는 모든 클라이언트 쪽). 디자인의 절충.

언젠가 마이그레이션을 수행해야하는 상황을 고려하여 애플리케이션으로 돌아와서 원래 분배 한 스키마보다 수십 개 이상의 속성이 있음을 발견하십시오. 따라서 엔터티 속성 값 테이블을 올바르게 사용하면 더 깔끔한 마이그레이션 및 업그레이드가 가능합니다. (항상 그런 것은 아니지만 가능합니다.)


런타임에 스키마를 수정하는 데 단점이 있습니까? 사물에 새로운 속성이 필요하다고 생각되면 테이블에 열을 동적으로 추가하면됩니까?

적절한 nosql 데이터베이스 버전으로 작업하는 경우이 작업을 수행 할 수 있습니다 (nosql의 적절한 버전은 아마도 위에서 설명한 관계형 데이터베이스 에 대한 EAV 테이블 인 키-값 저장소 일 것입니다). 너무 많은 어려움없이. 그러나 nosql에 대한 모든 타협은 다른 곳에서 자세히 설명되어 있습니다.

대신 관계형 데이터베이스에서 작업하는 경우 스키마가 있어야합니다. 열을 동적으로 추가하면 다음 사항 중 일부가 적용됩니다.

  • 메타 데이터베이스 프로그래밍을하고 있습니다. 이 ORM을 사용 하여이 열을 해당 필드에 깨끗하게 매핑하는 대신 select *데이터를 실제로 확인하기 위해 ( Java의 ResultSetMetaData 참조) 같은 작업을 수행 한 다음 복잡한 코드를 수행 하여 맵에 저장합니다 ( 또는 다른 데이터 유형- 코드의 멋진 필드는 아닙니다 ). 그러면 전통적인 접근 방식과 함께 약간의 유형과 오타가 발생하지 않습니다.
  • 귀하는 ORM을 포기했을 것입니다. 이것은 시스템이 당신을 위해 일하는 대신 모든 코드에 대해 원시 SQL을 작성하고 있음을 의미합니다.
  • 당신은 깨끗한 업그레이드를 포기했습니다. 고객이 다음 버전에서도 사용하는 하나의 이름을 가진 필드를 추가하면 어떻게됩니까? 매치 메이킹 사이트에서 hasdate타임 스탬프를 저장하기 위한 필드 를 추가하려는 업그레이드 는 이미 hasdate성공적인 일치를위한 부울 로 정의되었으며 업그레이드가 중단되었습니다.
  • 귀하는 고객이 귀하의 쿼리도 어딘가에 예약어를 사용하여 시스템을 중단하지 않는다고 믿습니다.
  • 하나의 데이터베이스 브랜드에 자신을 묶었습니다. 다른 데이터베이스 의 DDL 이 다릅니다. 데이터베이스 유형이 가장 쉬운 예입니다. varchar2text등. 열을 추가하는 코드는 MySQL에서는 작동하지만 Postgres, Oracle 또는 SQL Server에서는 작동하지 않습니다.
  • 고객이 실제로 데이터를 추가한다고 믿 습니까? 물론, EAV는 이상적이지는 않지만 이제는 개발자가 추가하지 않은 끔찍한 불명확 한 테이블 이름을 얻었습니다 (잘못된 유형의 색인이있는 경우). 등등.
  • 응용 프로그램을 실행하는 사용자에게 스키마 수정 권한을 부여했습니다. Little Bobby Drop Tables 는 DDL이 아닌 SQL로 제한되어있을 때 가능하지 않습니다 ( delete * from students대신 할 수는 있지만 실제로 데이터베이스를 엉망으로 만들 수는 없습니다). 사고 나 악의적 인 활동으로 인한 스키마 액세스로 잘못 될 수있는 것의 수.

이것은 실제로 "하지 마십시오"로 귀결됩니다. 실제로 원하는 경우 EAV 테이블 구조의 알려진 패턴 또는이 구조 전용의 데이터베이스를 사용하십시오. 사람들이 테이블에 임의의 필드를 만들게하지 마십시오. 두통은 그만한 가치가 없습니다.


4
또한 데이터베이스를 재창조했습니다.
user253751

1
@immibis는 사용자가 나머지 데이터베이스를 조작하거나 모델을 업데이트하기 위해 재배치하지 않고도 관리 할 수있는 계층을 추가했습니다.

1
@immibis EAV는 관계형 데이터베이스 분야에서 수년간 뜨거운 논쟁을 벌였습니다. 이론적으로는 불필요하지만 실제로는 특정 일 없이는 할 수 없습니다.
로스 패터슨

1
NoSQL 접근 방식으로 넘어가는 @ShivanDragon. 문서 저장소는 문서 만 저장하며 스키마를 강요하지 않습니다. 따라서 필드를 추가 및 제거하고 문서를 구문 분석하는 것은 데이터베이스 자체의 범위를 완전히 벗어납니다 (그리고이를 수용하기 위해 모델을 작성했습니다). EAV 구조에 대한 관계형 데이터베이스 손상과는 완전히 다른 손상입니다.


5

이것을 잘하는 것은 어렵다.

계획중인 것과 같은 일회성 응용 프로그램의 경우 물론 각 필드에 열을 추가하고 훈련되지 않은 사용자가 SQL 명령 줄을 제공하는 것보다 필드 정의를 더 안전하게 만드는 UI를 제공 할 수 있습니다. 또는 두려운 Entity-Attribute-Value 패턴을 따를 수도 있습니다.이 패턴은 다소 무섭지 만 이러한 종류의 문제에 대한 고전적인 반응입니다. EAV 필드를 정의하기위한 UI를 구축하는 것은 일반적으로 데이터베이스 열보다 훨씬 복잡하며 쿼리가 매우 복잡해 지지만 많은 수의 필드 ( : 매우 희소 행렬 스키마)에 대한 유일한 방법 일 수 있습니다. 작업이 완료되었습니다.


요약하면 : little project == KISS. 땅에 민첩하다.
Encaitar

데이터베이스 테이블 업데이트의 문제점은 데이터 양과 필요한 인덱스 (사용자 정의 필드에 종종 검색 기능이 필요함)에 따라 테이블 변경 쿼리에 엄청난 시간이 걸릴 수 있다는 것입니다. 간단히 말해 MySQL 및 기타 관계형 데이터베이스는 이러한 요구 사항에 적합한 매체가 아니라는 것입니다.
Oddman

0

최근에 비슷한 일이 생겼습니다.

나는 2 개의 테이블을 만들었습니다.

1: table Objects 
    Id , name, type

그는 당신의 모든 대상입니다. U는 그것의 이름을 설정합니다.

그리고이 객체의 유형 :-사용 가능한 유형은 inventory, inventory_item, office입니다.

그리고 일반적인 설정은 n 항목이 하위 또는 인벤토리 인 하위 항목이며 조인 테이블을 사용하여 객체를 서로 조인했습니다.

2 table settings 
     organization_Id , title, value , type

설정 테이블에는 해당 특정 객체 유형의 모든 필드 이름과 값이 포함되어 있습니다.

사무실의 속성 예

위치, 전화, 근무 시간

그리고 아이템

  • 가격
  • 바코드

기타, 이러한 모든 속성은 모델에 의해 시행되고 설정 테이블에 별도의 행으로 저장됩니다 (동일한 필드에 대해 여러 행을 피하기 위해 바꾸기를 사용하지 마십시오)

따라서 사무실을 원할 때마다 object_I 설정이있는 모든 관계 및 설정으로 쉽게로드 할 수 있습니다 (요청 된 객체)

그 후 설정에서 모든 행을 피벗하면됩니다.

그리고 인벤토리의 항목 (전역이 아닌)에 특정 설정을 원할 경우 object_I'd = I 'd를 object_objects relations 테이블에서 설정하고 settings.type = relation_setting을 설정했습니다.

랩톱에 도착했을 때 답변을 다시 포맷하려고한다는 의미를 이해하기를 바랍니다.


2
전문가 팁-휴대 전화에서이 포럼에 게시하지 마십시오. 자동 수정 기능으로 게시물의 일부를 읽을 수 없습니다.
BobDalgleish

Haha nice 관찰 :)
Zalaboza

0

사용자 정의 필드를 허용하는 것은 나쁜 습관입니까?

아니요, 나쁜 습관이 아닙니다. 꽤 일반적입니다. OO 용어에서는 이것을 상속이라고합니다. 기본 클래스 inventoryItem과 두 개의 상속 된 클래스 AudioCD 및 가구가 있습니다.

그러나 일반적으로 사람들은 "실제"에서 이와 같은 것을 어떻게 처리합니까?

inventoryItem, AudioCD 및 가구가 데이터베이스에 저장되는 방법을 결정해야합니다.

쉬운 쿼리가 가장 중요하고 db-space / normalisation이 중요하지 않은 경우 "계층 별 테이블"스키마를 구현합니다.

공간 / 정규화가 가장 중요하고 더 복잡한 쿼리가 문제가되지 않으면 "테이블 당"스키마를 구현해야합니다.

자세한 내용은 dotnet table-per-type-vs-table-per-hierarchy-inheritance 또는 java hibernate inheritance를 참조하십시오 .


이것이 문제를 해결하는지 모르겠습니다. 사용자는 새로운 클래스를 생성하기 위해 코드를 수정하지 않습니다
Colin D
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.