[database] 데이터베이스 열에 구분 목록을 저장하는 것이 실제로 그렇게 나쁩니 까?

확인란 세트가있는 웹 양식을 상상해보십시오 (일부 또는 모두 선택할 수 있음). 데이터베이스 테이블의 한 열에 저장된 값을 쉼표로 구분 된 값 목록에 저장하기로했습니다.

이제 올바른 해결책은 두 번째 테이블을 만들고 데이터베이스를 올바르게 정규화하는 것입니다. 쉬운 솔루션을 구현하는 것이 더 빨랐으며 너무 많은 시간을 들이지 않고도 해당 애플리케이션의 개념 증명을 신속하게 원했습니다.

절약 된 시간과 간단한 코드가 제 상황에서 가치가 있다고 생각했습니다. 이것이 방어적인 디자인 선택입니까, 아니면 처음부터 정규화해야합니까?

좀 더 많은 맥락에서 이것은 공유 폴더에 저장된 Excel 파일을 본질적으로 대체하는 작은 내부 응용 프로그램입니다. 나는 또한 프로그램을 정리하고 더 유지하기 쉽게 만드는 것에 대해 생각하고 있기 때문에 묻습니다. 거기에 내가 완전히 만족하지 않는 것들이 있습니다. 그중 하나 가이 질문의 주제입니다.



답변

단일 열에 저장된 반복되는 값 그룹으로 인해 첫 번째 정규형 을 위반하는 것 외에도 쉼표로 구분 된 목록에는 다른 여러 가지 실질적인 문제가 있습니다.

  • 각 값이 올바른 데이터 유형인지 보장 할 수 없음 : 1,2,3, 바나나, 5 를 막을 방법 없음
  • 외래 키 제약 조건을 사용하여 값을 조회 테이블에 연결할 수 없습니다. 참조 무결성을 강화할 방법이 없습니다.
  • 독창성을 강요 할 수 없음 : 1,2,3,3,3,5
  • 전체 목록을 가져 오지 않고 목록에서 값을 삭제할 수 없습니다.
  • 문자열 열에 맞는 것보다 더 긴 목록을 저장할 수 없습니다.
  • 목록에서 지정된 값을 가진 모든 엔티티를 검색하기가 어렵습니다. 비효율적 인 테이블 스캔을 사용해야합니다. 예를 들어 MySQL과 같은 정규식에 의존해야 할 수도 있습니다.
    idlist REGEXP '[[:<:]]2[[:>:]]'*
  • 목록의 요소를 계산하거나 다른 집계 쿼리를 수행하기가 어렵습니다.
  • 참조하는 조회 테이블에 값을 결합하기가 어렵습니다.
  • 정렬 된 순서로 목록을 가져 오기가 어렵습니다.

이러한 문제를 해결하려면 수많은 응용 프로그램 코드를 작성하여 RDBMS가 이미 훨씬 더 효율적으로 제공 하는 기능을 다시 개발해야합니다 .

쉼표로 구분 된 목록은이 책을 내 책의 첫 번째 장으로 만들 정도로 충분히 잘못되었습니다. SQL Antipatterns : 데이터베이스 프로그래밍의 함정 피하기 .

비정규 화를 사용해야 할 때가 있지만 @OMG Ponies가 언급했듯이 예외는 예외입니다. 관계형이 아닌 “최적화”는 다른 유형의 데이터 사용을 희생하여 한 가지 유형의 쿼리에 도움이되므로 비정규 화를 수행 할 수 있도록 특별히 처리해야하는 쿼리를 알고 있어야합니다.


* MySQL의 8.0 더 이상이 단어 경계를 표현 구문을 지원하지 않습니다.


답변

“한가지 이유는 게으름이었다”.

알람 벨이 울립니다. 이와 같은 일을해야하는 유일한 이유는 “올바른 방법”으로하는 방법을 알고 있지만 그렇게하지 않는 확실한 이유가 있다는 결론에 도달했기 때문입니다.

이렇게 말한 경우 :이 방법으로 저장하려는 데이터가 쿼리 할 필요가없는 데이터 인 경우 선택한 방식으로 데이터를 저장하는 경우가있을 수 있습니다.

(일부 사용자는 앞의 단락에서“앞으로 어떤 요구 사항이 추가 될지 알 수 없습니다”라는 진술에 이의를 제기 할 수 있습니다. 당신 앞에 있습니다.)


답변

SO 요청에 대한 수많은 질문이 있습니다.

  • 쉼표로 구분 된 목록에서 특정 값의 개수를 얻는 방법
  • 쉼표로 구분 된 목록에서 동일한 2 / 3 / etc 특정 값만있는 레코드를 얻는 방법

쉼표로 구분 된 목록의 또 다른 문제는 값이 일관성을 유지하는 것입니다. 텍스트를 저장하면 오타가 발생할 가능성이 있습니다.

이는 모두 비정규 화 된 데이터의 증상이며 항상 정규화 된 데이터를 모델링해야하는 이유를 강조합니다. 비정규 화 요구가 실제로 제시 될 때 적용되는 쿼리 최적화 일 수 있습니다 .


답변

일반적으로 프로젝트 요구 사항을 충족하면 방어 할 수 있습니다. 이것은 사람들이 당신의 결정에 동의하거나 방어하기를 원한다는 의미는 아닙니다 …

일반적으로 이러한 방식으로 데이터를 저장하는 것은 차선책이므로 (예 : 효율적인 쿼리를 수행하기가 더 어렵습니다) 양식에서 항목을 수정하면 유지 관리 문제가 발생할 수 있습니다. 아마도 중간 접지를 발견하고 대신 비트 플래그 세트를 나타내는 정수를 사용했을 수 있습니까?


답변

그렇습니다, 나는 그것이 정말로 나쁘다고 말합니다. 그것은 선택의 여지가 있지만 그것이 정확하거나 좋지는 않습니다.

첫 번째 정상적인 형태를 break습니다.

두 번째 비판은 유효성 검사 나 바인딩없이 원시 입력 결과를 데이터베이스에 직접 넣는 것이 SQL 인젝션 공격에 노출된다는 것입니다.

게으름과 SQL 지식의 부족이라고 부르는 것은 신생 생물이 만들어내는 것입니다. 시간을내어 제대로하고 배우는 기회로 여길 것을 권합니다.

또는 그대로두고 SQL 주입 공격에 대한 고통스러운 교훈을 배우십시오.


답변

글쎄, 지금 4 년 이상 SQL Server의 NTEXT 열에서 키 / 값 쌍 탭으로 구분 된 목록을 사용 해 왔으며 작동합니다. 쿼리의 유연성을 잃지 만 반면에 키 값 쌍을 유지 / 제거하는 라이브러리가 있다면 그렇게 나쁜 생각이 아닙니다.


답변

다중 값 열이 필요했습니다 .xml 필드로 구현할 수 있습니다.

필요에 따라 쉼표로 구분하여 변환 할 수 있습니다.

XQuery를 사용하여 SQL Server에서 XML 목록을 조회 .

xml 필드이기 때문에 일부 문제를 해결할 수 있습니다.

CSV 사용 : 각 값이 올바른 데이터 유형인지 보장 할 수 없음 : 1,2,3, 바나나, 5를 막을 방법 없음

XML을 사용하면 태그의 값을 올바른 유형으로 만들 수 있습니다.


CSV 사용 : 외래 키 제약 조건을 사용하여 값을 조회 테이블에 연결할 수 없습니다. 참조 무결성을 강화할 방법이 없습니다.

XML로 : 여전히 문제


CSV 사용 : 고유성을 강제 할 수 없음 : 1,2,3,3,3,5를 방지 할 수있는 방법이 없습니다

XML로 : 여전히 문제


CSV 사용 : 전체 목록을 가져 오지 않고 목록에서 값을 삭제할 수 없습니다.

XML : 단일 항목을 제거 할 수 있습니다


CSV 사용 : 목록에서 지정된 값을 가진 모든 엔티티를 검색하기가 어렵습니다. 비효율적 인 테이블 스캔을 사용해야합니다.

XML : XML 필드를 색인 할 수 있습니다


CSV 사용 : 목록에서 요소를 계산하기 어렵거나 다른 집계 쿼리를 수행합니다. **

XML로 : 특별히 어렵지 않은


CSV : 값을 참조하는 조회 테이블에 결합하기가 어렵습니다. **

XML로 : 특별히 어렵지 않은


CSV 사용 : 목록을 정렬 된 순서로 가져 오기가 어렵습니다.

XML로 : 특별히 어렵지 않은


CSV 사용 : 정수를 문자열로 저장하면 이진 정수를 저장하는 것보다 두 배의 공간이 필요합니다.

XML을 사용하면 스토리지가 CSV보다 더 나빠집니다.


CSV 사용 : 많은 쉼표 문자.

XML 사용 : 쉼표 대신 태그가 사용됨


요컨대, XML을 사용하면 구분 된 목록의 일부 문제가 발생하고 필요에 따라 구분 된 목록으로 변환 할 수 있습니다