열거 형 데이터 형식을 사용하는 대신 새 데이터베이스 테이블을 만드는 것이 낭비입니까?


38

내가 제공하는 4 가지 유형의 서비스가 있다고 가정합니다 (빈번히 변경되지는 않음).

  • 테스팅
  • 디자인
  • 프로그램 작성
  • 다른

각각 위의 범주 중 하나에 해당하는 60-80 개의 실제 서비스가 있다고 가정합니다. 예를 들어, "서비스"는 "기술 A를 사용한 테스트 프로그램"일 수 있으며 "테스트 중"유형입니다.

데이터베이스로 인코딩하고 싶습니다. 몇 가지 옵션을 생각해 냈습니다.

옵션 0 :

VARCHAR서비스 유형을 직접 문자열로 인코딩하는 데 직접 사용

옵션 1:

데이터베이스를 사용하십시오 enum. 그러나 열거 형은 악하다

옵션 2 :

두 개의 테이블을 사용하십시오.

service_line_item (id, service_type_id INT, description VARCHAR);
service_type (id, service_type VARCHAR);

참조 무결성을 즐길 수도 있습니다.

ALTER service_line_item 
    ADD FOREIGN KEY (service_type_id) REFERENCES service_type (id);

그래요?

그러나 나는 여전히 테이블을 채울 때 물건을 인코딩하고 정수를 처리해야합니다. 또는 테이블을 채우거나 처리 할 때 정교한 프로그래밍 또는 DB 구성을 만들어야합니다. 즉, 데이터베이스를 직접 처리하거나 프로그래밍 측에서 새로운 객체 지향 엔터티를 생성하고 올바르게 작동하는지 확인할 때 참여하십시오.

옵션 3 :

을 사용 enum하지 말고 두 테이블을 사용하지 말고 정수 열만 사용하십시오.

service_line_item (
    id,
    service_type INT,        -- use 0, 1, 2, 3 (for service types)
    description VARCHAR
);

이것은 코드 측면에서 더 많은 오버 헤드가 필요한 '가짜 열거 형'과 같습니다. 즉,이를 알고 {2 == 'Programming'}적절히 처리 하는 것과 같습니다 .

질문:

현재 개념 2 에 따라 옵션 2를 사용하여 구현했습니다.

  1. 열거 형을 사용하지 마십시오 (옵션 1)
  2. 데이터베이스를 스프레드 시트로 사용하지 마십시오 (옵션 0)

그러나 프로그래밍과인지 오버 헤드 측면에서 나에게 낭비되는 것처럼 느껴질 수는 없습니다. 두 테이블을 알고 두 테이블을 처리해야합니다.

'더 적은 낭비 방법'을 위해, 나는보고있다 Option 3. IT는 더 가볍고 작동하려면 기본적으로 동일한 코드 구성이 필요합니다 (약간의 수정이 있지만 복잡성과 구조는 기본적으로 동일하지만 단일 테이블을 사용함)

이상적으로 항상 낭비가 아니며 옵션에 대한 좋은 사례가 있지만 옵션 2를 사용해야 할 때와 옵션 3을 사용해야 할 때 좋은 지침이 있습니까?

두 가지 유형 (이진) 만있는 경우

같은 장소에서이 질문에 조금 더 추가하려면 "표준"또는 "예외"서비스의 이진 옵션을 사용하면 서비스 광고 항목에 적용될 수 있습니다. 옵션 3 을 사용하여 인코딩했습니다 .

{ "Standard", "Exception"} 값을 보유하기 위해 새 테이블을 작성하지 않기로 선택했습니다. 그래서 내 열은 {0, 1}을 유지하고 열 이름은 exception이고 코드는 번역을 수행합니다 {0, 1} => {STANDARD, EXCEPTION}(프로그래밍 언어에서 상수로 인코딩 됨)

지금까지는 그 방법을 좋아하지 않았습니다 ..... (옵션 2 또는 옵션 3을 좋아하지 않음). 옵션 2가 3보다 우수하지만 더 많은 오버 헤드가 있지만 2와 3 중 어느 옵션을 사용하든 정수로 인코딩을 피할 수는 없습니다.

ORM

컨텍스트를 추가하려면 답변을 읽은 후-필자의 경우 Doctrine 2에서 ORM을 다시 사용하기 시작했습니다. 주석을 통해 DB 스키마를 정의한 후 데이터베이스를 채우고 싶었습니다. 전체 데이터 세트가 상대적으로 작기 때문에 프로그래밍 구문을 사용하여 작동 방식을 확인하고 싶었습니다.

실제 스프레드 시트의 기존 목록이 있으므로 먼저 service_types를 입력 한 다음 service_line_items를 입력했습니다. 따라서 'standard / exception'및 'Testing'과 같은 것은 스프레드 시트의 모든 문자열이며 DB에 저장하기 전에 적절한 유형으로 인코딩해야합니다.

나는 SO 답변을 발견했다 : doctrine2에서 ENUM 대신 무엇을 사용합니까? DB의 enum 구문을 사용하지 말고 INT프로그래밍 언어의 'const'구문 을 사용하여 필드를 사용하고 형식을 인코딩하도록 제안했습니다 .

그러나 위의 SO 질문에서 지적했듯이 정수를 직접 사용하지 말고 일단 정의 된 언어 구조 (상수)를 사용할 수 있습니다 ...

그러나 여전히 .... 어떻게 돌리 든 관계없이 string유형으로 시작 하면 ORM을 사용할 때도 먼저 올바른 유형으로 변환해야합니다.

따라서라고 말하면 $str = 'Testing';여전히 다음과 같은 작업을 수행하는 블록이 필요합니다.

switch($str):
{ 
    case 'Testing':  $type = MyEntity::TESTING; break;
    case 'Other':    $type = MyEntity::OTHER; break;
}

좋은 점은 정수 / 매직 숫자를 처리하지 않고 (인코딩 된 상수 수량을 처리하는 것), 나쁜 점은이 변환 단계없이 데이터베이스에서 자동으로 데이터를 가져오고 꺼낼 수 없다는 것입니다. 지식.

그리고 그것은 부분적으로, "여전히 일을 인코딩하고 정수를 처리해야합니다"와 같은 것을 말함으로써 의미 한 것입니다. (지금, Ocramius의 의견에 따라 정수를 직접 처리 할 필요는 없지만 명명 된 상수와 필요에 따라 상수로 /로부터의 변환을 처리해야합니다).


9
당신이 무엇을 하든지 # 3을하지 마십시오. 그것을 유지하는 정신병자는 끊임없이 그 마법의 숫자가 무엇을 의미하는지 알아 내야 할 것입니다. 그렇게한다면 그들이 사는 곳을 모르기를 바랍니다. blog.codinghorror.com/coding-for-violent-psychopaths
RubberDuck

7
옵션 2가 마음에 듭니다. 조회 테이블의 확산이 마음에 들지 않으면 하나의 테이블을 사용하고 "조회 유형"열을 추가하십시오. 그러나 룩업 테이블을 작성하는 것은 UI에서 드롭 다운을 쉽게 채우는 것과 같은 재미있는 작업을 수행 할 수있게 해주는 "표준"방법입니다.
Robert Harvey

귀하의 게시물에 "편집"을 사용하지 마십시오. 우리는 포럼이 아닙니다. 모든 Stack Exchange 게시물에는 이미 누구나 볼 수 있는 자세한 편집 기록 이 포함되어 있습니다.
Robert Harvey

EDIT를 사용할 수 없으면 무엇을 사용해야합니까?
Dennis

글을 편집하고 이미 해본 것처럼 자연스럽게 보이게하십시오. 변경 사항을 검토 하려면 편집 히스토리 를 참조하십시오 .
Robert Harvey

답변:


35

참조 테이블을 사용하는 옵션 # 2는이를 수행하는 표준 방법입니다. 수백만 명의 프로그래머가 사용했으며 작동하는 것으로 알려져 있습니다. 그것은이다 패턴 물건을보고 다른 사람이 즉시에 무슨 일이 일어나고 있는지 알 수 있도록. 데이터베이스에서 작동하는 라이브러리와 도구가 존재하여 올바르게 처리 할 수있는 많은 작업을 줄일 수 있습니다. 그것을 사용하는 이점은 무수합니다.

낭비입니까? 예, 그러나 약간만 있습니다. 절반 정도의 데이터베이스는 항상 빈번하게 조인 된 작은 테이블을 캐시 된 상태로 유지하므로 낭비는 일반적으로 인식되지 않습니다.

설명한 다른 모든 옵션 enum은 SQL 표준을 포함하지 않으므로 MySQL을 포함하여 특별하고 해킹 적 입니다. (그 외에는 enum아이디어 자체가 아닌 MySQL의 구현이 중요 합니다. 언젠가는 표준의 일부로 보지 않아도됩니다.)

일반 정수를 사용하는 최종 옵션 # 3은 특히 해키입니다. 참조 무결성, 명명 된 값, 값의 의미에 대한 데이터베이스 내에서 확실한 지식, 모든 곳에서 발생하는 임의의 정수 등 모든 세계에서 최악의 결과를 얻습니다. 이 토큰을 사용하면 코드에서 상수 사용을 끝내고 대신 하드 코딩 된 값을 사용할 수 있습니다. circumference = radius * 6.28318530718;. 어떻게에 대한?

참조 테이블이 번거로운 이유를 다시 검토해야한다고 생각합니다. 내가 아는 한 아무도 다른 사람들을 괴롭히지 않습니다. 작업에 적합한 도구를 사용하지 않았기 때문일 수 있습니까?

"사물을 인코딩하고 정수를 처리해야"하거나 "정교한 프로그래밍 구조를 생성"하거나 "프로그래밍 측면에서 새로운 객체 지향 엔티티를 생성"해야한다는 문장은 아마도 당신이 객체 관계형을 시도하고 있다고 말할 수 있습니다. 즉석에서 매핑 (ORM)은 응용 프로그램의 코드 전체에 분산되어 있거나 최상의 경우에는 Hibernate와 같은 작업에 기존 ORM 도구를 사용하는 대신 고유 한 객체 관계형 매핑 메커니즘을 롤링하려고 할 수 있습니다. 이 모든 것들이 최대 절전 모드에서 산들 바람입니다. 배우는 데 약간의 시간이 걸리지 만 일단 배우면 응용 프로그램 개발에 집중하고 데이터베이스에서 물건을 나타내는 방법의 핵심 메커니즘을 잊을 수 있습니다.

마지막으로, 데이터베이스로 직접 작업 할 때 삶을 편하게 만들고 싶다면 지금 생각할 수있는 최소한 두 가지가 있습니다.

  1. 각 행에 참조 ID뿐만 아니라 해당 이름도 포함되도록 기본 테이블을 참조하는 참조 테이블과 결합하는 뷰를 작성하십시오.

  2. 참조 테이블에 정수 ID를 사용하는 대신 4 자 약어가있는 CHAR (4) 열을 사용하십시오. 따라서 카테고리의 ID는 "TEST", "DSGN", "PROG", "OTHR"이됩니다. (그들의 설명 은 물론 적절한 영어 단어로 남을 것입니다.) 조금 느려질 것입니다. 그러나 아무도 믿지 않습니다.

마지막으로 두 가지 유형 만있는 경우 대부분의 사람들은 부울 열을 사용합니다. 따라서 "표준 / 예외"열은 부울로 구현되며 "IsException"이라고합니다.


3
그 외에도 Postgres에는 enum 유형 도 있습니다. 그것들은 단순하고 특별한 것이 없으므로 읽을 수있는 문자열을 값으로 사용할 수 있지만 더 효율적인 정수를 사용할 수 있습니다.
Kat

결과적으로 데이터가 반복되지만 중복되지 않는 경우 (예 : 업데이트 / 삽입 / 삭제 이상이 발생하지 않는 경우)는 어떻습니까? 예를 들어, 개인의 성별 (새로운 데이터 유형을 도입하지 않아도 성별 이름을 변경할 필요는 없음 등)
Adam Thompson

결국 : "수락 환경"이 필요하고 변경되지 않는 열거 형을 변경해야한다는 사실을 알게 될 것입니다.
Pieter B

3

프로그래밍 끝에 상수 또는 열거가있는 옵션 2
단일 소스 원칙의 원칙에 위배되는 지식을 복제하지만 Fail-fast 기술 을 사용하여 처리 할 수 ​​있습니다 . 시스템이로드되면 열거 형 또는 const 값이 데이터베이스에 있는지 확인합니다. 그렇지 않으면 시스템에 오류가 발생하고로드를 거부해야합니다. 더 심각한 일이 발생했을 때보 다 나중에이 버그를 수정하는 것이 일반적으로 더 저렴합니다.


0

[짧은] 문자열을 키로 사용하는 것을 막을 방법이 없으므로 테이블에서 이름을 읽을 수 있고 의미없는 대리 숫자 인코딩을 사용하지 않아도됩니다. 서비스 유형을 설명하기위한 별도의 테이블이 여전히 있어야합니다.

귀하의 사용자에 네 가지 범주를 볼 수 있습니다 자신의 언어, 그러나 당신의 데이터베이스 테이블은 여전히 값이 포함되어 당신이 읽을 수 - 그것의 어느 것도 데이터베이스 구조 또는 코드를 변경할 필요가 없습니다!

table service_type 
( id VARCHAR 
, name VARCHAR 
  primary key ( id ) 
);
table service_line_item 
( id 
, service_type VARCHAR 
, description VARCHAR
  foreign key ( service_type ) references service_type ( id )
);

select * from service_type ; 

+-------------+----------------+
| id          | name           |
+-------------+----------------+
| Testing     | Testen         |
| Design      | Design         | 
| Programming | Programmierung |
| Other       | Andere         |
+-------------+----------------+

또는 프랑스 고객의 경우 ...

update services_types set name = 'Essai'         where id = 'Testing'; 
update services_types set name = 'Conception'    where id = 'Design'; 
update services_types set name = 'Programmation' where id = 'Programming'; 
update services_types set name = 'Autre'         where id = 'Other'; 
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.