별도의 행이 아닌 한 행의 한 필드에 여러 값을 저장하면 얻을 수있는 이점


11

지난 주 회의에서 데이터베이스 관리에 대한 경험이없는 사람이이 질문을 제기했습니다.

"여러 줄 대신 인라인 (문자열) 데이터 저장을 정당화하는 시나리오가 있습니까?"

countryStates국가의 상태를 어디에 저장하고 싶은지 테이블을 가정 해 봅시다 . 이 예에서는 USA를 사용하고 게으름을 위해 모든 국가를 나열하지는 않습니다.

거기에는 두 개의 열이 있습니다. 하나는 호출 Country되었고 다른 하나는 호출했습니다 States. 여기 에서 논의 되고 @srutzky의 답변 에서 제안한 바와 같이 ISO 3166-1 alpha-3에PK 의해 정의 된 코드가 될 것 입니다.

우리의 테이블은 다음과 같습니다.

+---------+-----------------------+-------------------------------------------------------+
| Country | States                | StateName                                             |
+---------+-----------------------+-------------------------------------------------------+
| USA     | AL, CA, FL,OH, NY, WY | Alabama, California, Florida, Ohio, New York, Wyoming |
+---------+-----------------------+-------------------------------------------------------+

그는 같은 질문을 친구 개발자에게 요청할 때 데이터 트래픽 크기 관점에서이 방법이 유용 할 수 있지만이 데이터를 조작 할 필요는 없다고 말했다. 이 경우 목록에서이 문자열을 변환 할 수있는 응용 프로그램 코드에 대한 정보가 있어야합니다 (이 테이블에 액세스 할 수있는 소프트웨어가 콤보 상자를 만들어야 함).

우리는이 모델이 그다지 유용하지 않다는 결론을 내렸지 만,이 모델을 유용하게 만드는 방법이 있을지 의심 스럽다.

내가 묻고 싶은 것은 여러분 중 누군가가 실제로 작동 하는 방식으로 이미 이런 말을 보거나 듣거나했는지 여부 입니다.


이제 판매가 발생한 주 코드와 함께 발생한 모든 판매에 대한 데이터가있는 "판매"라는 두 번째 테이블이 있다고 가정하십시오. 열 (StateName, TotalSalesAmount)이있는 보고서를 생성하는 쿼리를 어떻게 작성 하시겠습니까? 어려운가요?
zgguy

바로 그거죠. 나는 또한이 모델에 동의하지 않습니다. 우리는 모든 유형의 데이터 (또는 유용한 데이터)를 복구해야하는 시점에 멈춰 있습니다.
Human_AfterAll

가능한 시나리오는 변수를 저장하는 것입니다. 스토어 a;b;c, 다음 문자열 당신을 구문 분석 얻을 수있는 프론트 엔드를 사용 a, b, c어쩌면 그들과 함께 일을하고 실행에와 캐리를? 그런 식으로 특정 요구에 맞을 수도 있다고 생각합니다. 당신은 항상 ID를 저장하고, 테이블에 가입하고, FE에 콘텐츠를 보낼 수있는 것보다 연결된 문자열을 만들 수 있습니다.
Nelz

공정하게 (적어도 ;-), 나는 다른 답변 에서 2 자 국가 코드 :-) 사용을 제안했습니다 .
Solomon Rutzky

2
"상태 STATE의 이름은 N 번째 문자 C"에 대해 STATE, N & C 열이있는 별도의 테이블을 가지지 않고 열에 "Alabama"값을 저장하는 것에 대한 자격이 없습니다. 왜냐하면 1. 우리는 이름의 문자에 대해 쿼리하지 않을 것입니다. 또는 2. . (VS JOIN 및 기타 관계 연산자는 여분의 테이블을 통해 이러한 행을 제거합니다.) 정수 및 NTH_DIGIT (N, I)에 대한 Ditto. 특정 데이터베이스에서 관계형 원자가 무엇인지에 대한 판단은 항상 요구됩니다.
philipxy

답변:


13

우선, "질문 대신 문자열로 데이터 저장"을 참조하는 현재 질문 제목은 약간 혼동됩니다. 데이터를 다른 것으로 대신 문자열로 저장하는 경우 일반적으로 모든 데이터를 적절한 / 강력한 데이터 유형 (예 : INT또는 DATETIME) 대신 문자열 형식으로 직렬화하는 것을 말합니다 . 그러나 데이터를 별도의 행이 아닌 단일 필드에 여러 값으로 저장하는 것이 조금 다른 경우. 그리고 공평하게 말하면 문자열을 사용하여 값을 연결하는 것이 가장 쉽게 수행 되지만 비트 마스킹 또는 유사하게 특정 위치를 예약하여 다른 의미를 갖도록 사용 INT하여 BINARY유형을 지정할 수도 있습니다 . 두 번째 해석은 질문의 내용을 바탕으로 실제로 요청되는 내용이므로이를 다루겠습니다.

한마디로 : 아니요. 실제 데이터 포인트를 저장하는 경우 불필요한 합병증으로 인해 코드와 성능 측면에서 문제가 발생할 수 있습니다. 단일 단위로만 저장되고 단일 단위로 업데이트되며 데이터베이스 내에서 절대로 분해되지 않는 값이면 이미지 또는 PDF를 저장하는 것과 거의 유사하므로 괜찮을 수 있습니다. 또, 어떤 인덱스를 사용하여 무효화 데이터를 분석하려는 시도 (예를 들어, 사용 LIKE '%something%'하거나 CHARINDEX, 또는 PATINDEX, 또는 SUBSTRING등).

단일 행의 단일 필드에 별도의 값을 저장해야하는 경우 XML 또는 JSON과 같은 적절한 방법이 있습니다. 이것들은 구문 분석 가능한 형식 ( XML / JSON )이며 XML도 색인화 할 수 있습니다 . 그러나 이상적으로이 데이터는 올바른 유형의 필드에 저장되므로 실제로 유용 할 수 있습니다.

RDBMS의 목적은 ACID를 준수 함으로써 부과되는 제약 조건 내에서 가능한 한 효율적으로 검색 조작 할 수 있도록 데이터를 저장하는 것 입니다. 연결된 값을 검색하는 것은 먼저 값을 구문 분석해야하기 때문에 충분히 나쁘며 색인 할 수 없습니다. 그러나 조작은 종종 전체 블롭을 교체하여 일부를 업데이트하기 만합니다 ( 함수 에 사용할 패턴이 없다고 가정 ). XML 데이터 유형은 단순 업데이트를 위해 XML DML 을 허용 하지만, 여전히 올바르게 모델링 된 데이터를 업데이트하는 것만 큼 빠르지는 않습니다.REPLACE

또한 위의 질문에 표시된 것과 같은 시나리오에서 모든 StateCode를 함께 연결하면 해당 값을 외래 키 (양방향으로) 할 수 없습니다.

비즈니스 요구 사항이 시간이 지남에 따라 변경되고 이러한 항목의 추가 속성을 추적해야하는 경우 어떻게해야합니까? "국가"의 관점에서, 수도, 인구, 정렬 순서 또는 다른 어떤 것은 어떻습니까? 행으로 올바르게 저장하면 추가 속성에 대한 열을 더 추가 할 수 있습니다. 물론 여러 수준의 구문 분석 가능한 데이터를 가질 수는 |StateCode,Capital,Population |StateCode,Capital,Populate|...있지만 누구나 통제 할 수 없을 정도로 문제가 커질 수 있기를 바랍니다. 물론이 특정 문제는 XML 및 JSON 형식을 쉽게 처리 할 수 ​​있으며 위에서 언급 한대로의 가치입니다. 그러나 별도의 행에서 개별 필드를 사용하는 것만 큼 효율적이지는 않지만 모델링 방법 중 하나를 초기 모델링 수단으로 사용 하는 데는 여전히 충분한 이유 가 필요합니다 .


9

나는 실제로 매우 제한된 목적으로 그런 것을 사용했습니다. 출력 파일의 헤더 테이블을 만들었습니다. 그것들은 구체적으로 구성되었으며 주로 열 머리글 일 뿐이지 않았습니다. 데이터는 다음과 같습니다

OutputType   OutputHeader
PersonalData Name|Address|City|State|Zip
JobInfo      Name|JobName|JobTitle

본질적으로 그것은 구분 된 목록 인 것처럼 보였다. 그리고 한 가지 방식으로 그렇습니다. 그러나 우리의 목적을 위해 하나의 긴 문자열이었습니다.

이것이 속임수입니다. 목록을 구문 분석 하지 않으려는 경우 목록을 저장하는 것이 좋습니다. 그러나 목록을 구문 분석해야 할 필요가 있거나 목록을 구문 분석해야 할 경우 목록을 분리하여 별도의 행에 저장하는 데 추가 공간 및 시간이 필요합니다.


1

예를 들어 다소 작은 테이블로 한 번 사용했습니다.

CREATE TABLE t1 (
  ID number,
  some_feature   varchar2(100),
  valid_channels  varchar2(100));

CREATE TABLE channel_def (
  channel varchar2(100));

그리고 값을 저장 CRM,SMS,SELF-CAREvalid_channel.

전체 테이블에는 10 개의 레코드가 있습니다. valid_channel실제로는 다 대 다 관계를 나타내는 연결 테이블에 있어야하는 값을 포함합니다. 테이블 t1은 집중적으로 사용되지 않으므로 우리는이 길을 가기로 결정했습니다. 그러나 일부 정치가이 결정에 관여했습니다 (아래 참조).

그러나 일반적으로 나는 그것을 피합니다 .3NF가 아닙니다.

내가 현재 일하는 곳은 곳곳에 수십 개의 기둥이 있습니다. 연결 테이블을 사용하여 세 개의 테이블을 조인하는 대신을 사용하여 정의 테이블로 바로 이동할 수 있습니다 LIKE. 예 :

SELECT * 
  FROM t1 
 INNER JOIN channel_def cd
    ON ','||t1.valid_channels||',' LIKE '%,'||cd.channel||',%';

Oracle의 Horrible +는 시작으로 인해 인덱스 사용을 비활성화합니다 '%,'.


어느 것이 더 느릴 LIKE까요? 아니면 간단한 조인입니까?
Human_AfterAll

색인화되었거나 최소한 FK (참조 제한)가있는 열에 조인하는 것이 가장 좋습니다. 또한 조인은 일반적으로 다른 테이블의 PK에서 수행되며 기본적으로 (적어도 Oracle에서) 인덱싱됩니다. 특정 사례에 대해 묻는다면 (위 참조) 실행 계획은 작은 테이블이기 때문에 동일하다고 말할 것입니다.
Robotron

@Human_AfterAll은 LIKE특히 데이터가의 TINYINTPK 필드를 사용하도록 올바르게 모델링 된 경우 속도가 느려집니다 channel_def. 그런 다음 두 테이블 사이의 단일 바이트 만 비교하면됩니다. 여기서는 문자열을 문자 단위로 구문 분석해야하며 (적어도 조건이 충족 될 때까지) 대소 문자를 구분하지 않는 검색을 수행합니다 ( _BIN2사용중인 데이터 정렬을 표시하지 않는 주어진 테이블 def를 기반으로 함 ). 이렇게하면 SQL Server의 인덱스도 무효화됩니다. 파싱에서 인덱스를 사용할 수 없다는 말로 대답했습니다. 방금 명확하게 답변을 업데이트했습니다.
Solomon Rutzky

1
나는이 모델링 결정이 경험과 지식의 부족 ( 때로는 게으름)에서 비롯되었다고 말할 것 입니다. 하나의 추가 조인은 저장되는 모든 것이지만 희생되는 것은 외래 키 기능으로 완전히 가짜 데이터가 들어오는 것을 막을 수 있습니다 ( LIKE절과 일치하지 않고 이상한 결과를 생성 하더라도 여전히 다른 문제가 발생할 수 있음) 적어도 디버깅을 더 어렵고 길게 만듭니다. 또한 valid_channels필드 업데이트가 더 복잡해집니다. 이것은 단지 어떤이,이 작동하지 않는 것을 말하는 것이 아니다 좋은 그것을 수행하는 이유는.
Solomon Rutzky

"경험 부족"-최악의 상황은이 특정 설계 결정이 고위 직원에 의해 부과되었다는 것입니다.
Robotron

1

이것은 SE에서 이루어졌습니다. Marc Gravell의 글을 참고하세요 :

... 약간의 생각과 배려 후에, 우리는 선행 / 트레일 링 파이프와 함께 파이프 (바)로 구분 된 자연 표현에 정착 했으므로“.net c #”은 단순히“| .net | c # |”가됩니다. 이것은 장점이 있습니다.

  • 파싱하기 매우 간단
  • 태그의 대량 업데이트 및 제거는 간단한 교체 (파이프를 포함하여 태그 중간 일치를 교체하지 않음)로 수행 할 수 있습니다.
  • ...

이 "새 형식"은 약간 다른 "이전 형식"의 다음 단계였으며 SQL Server 전체 텍스트 검색 기능을 사용하도록 선택되었으므로 처음부터 다시 시작하면 일부 이점이 관련이 없습니다.

아마도 작업량과 성능상의 이유로 모두 정상화하지는 않았을 것입니다.


0

음, 문자열 및 기타 데이터 형식을 사용하면 얻을 수있는 주요 이점 중 하나는 성능이 필요할 때 SQLCLR을 사용하여 SQL Server에서 C #, C, C ++ 등으로 보내는 것입니다. 이 목적을 위해 위의 예에서와 같이 관계형 데이터를 비 관계형으로 나타내는 뷰 또는 저장 프로 시저를 만들 수도 있습니다.

이 예제를보십시오 :

http://aboutsqlserver.com/2013/07/22/clr-vs-t-sql-performance-considerations/

위키 백과 : SQL CLR 또는 SQLCLR (SQL 공용 언어 런타임)은 SQL Server 내에서 Microsoft .NET 공용 언어 런타임 엔진을 호스팅하기위한 기술입니다. SQLCLR을 사용하면 관리 코드를 Microsoft SQL Server 환경에서 호스팅하고 실행할 수 있습니다.


2
안녕. 자세한 내용을 알려주세요. 이것이 비 전통적인 방식으로 데이터를 저장하면 어떤 이점이 있는지 잘 모르겠습니다. 대체 데이터 형식이있는 경우 대체 데이터 형식을보다 잘 처리 할 수 ​​있으면 SQLCLR의 이점이 있습니다. 그러나 이것이 대체 데이터 형식을 선호하는 이유는 아닙니다. 따라서 나는 이것이 이것이 질문에 대답하지 않는다고 생각합니다.
Solomon Rutzky

기사 링크는 장단점의 이점을 설명합니다. 또한 데이터를 관계 적으로 저장하고 CLR을 위해 데이터를 뷰 또는 저장 프로 시저와 비 관계형으로 변환하는 것을 언급했습니다. 귀하의 질문은 "여러 줄 대신 인라인 (문자열) 데이터 저장을 정당화하는 시나리오가 있습니까?" CLR과 상호 작용하기 위해 뷰 또는 저장 프로 시저를 선호하지만 내 대답은 '예'입니다.
Sting

0

내 생각에 대답은 '아니오'입니다. 나는이 접근법을 사용하지 않았으며 피할 것이다. 나는 그 길을 따라가는 이유를 생각할 수 없다. 배열이있는 JSON / NoSQL의 세계에 기울고 있습니다.

우리는 건축가 팀이 "데이터"필드를 갖고 분리 된 다음 이진으로 변환하기를 원했던 이전의 역할에서 비슷한 디자인 선택을 가졌습니다. 우리는 몇 가지 이유로 결국 그 길을 내려 가지 않았습니다.

이 유형의 데이터에 참여해야한다면 경험이 한 가지가 아닙니다. 문자열의 단일 요소를 업데이트하는 것도 불쾌합니다.

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