더 효율적인 방법 : 여러 MySQL 테이블 또는 하나의 큰 테이블?


103

MySQL 데이터베이스에 다양한 사용자 세부 정보를 저장합니다. 원래는 데이터가 UserId와 연결되어 있고 필요에 따라 데이터를 표시하고 조작하는 복잡한 호출을 통해 출력하는 것을 의미하는 다양한 테이블에 설정되었습니다. 새로운 시스템을 설정하면 이러한 모든 테이블을 하나의 큰 관련 콘텐츠 테이블로 결합하는 것이 거의 합리적입니다.

  • 이것이 도움이 될까요 아니면 방해가 될까요?
  • 전화, 업데이트 또는 검색 / 조작시 속도 고려 사항?

다음은 내 테이블 구조의 일부 예입니다.

  • users-사용자 ID, 사용자 이름, 이메일, 암호화 된 비밀번호, 등록 날짜, IP
  • user_details-쿠키 데이터, 이름, 주소, 연락처 정보, 소속, 인구 통계 데이터
  • user_activity-기여, 마지막 온라인, 마지막보기
  • user_settings-프로필 표시 설정
  • user_interests-타겟팅 가능한 변수 광고
  • user_levels-액세스 권한
  • user_stats-조회수, 집계

편집 : 지금까지 모든 답변을 찬성했으며 모두 본질적으로 내 질문에 대답하는 요소가 있습니다.

대부분의 테이블은 비정규 화의 주된 이유 인 1 : 1 관계를 가지고 있습니다.

이러한 셀의 많은 부분이 비어있을 가능성이있는 경우 테이블이 100 개 이상의 열에 걸쳐 있으면 문제가 있습니까?


다른 질문은 너무 도움이 될 수
MOSTY Mostacho

답변:


65

여러 테이블은 다음과 같은 방법 / 사례에 도움이됩니다.

(a) 다른 사람들이 다른 테이블을 포함하는 응용 프로그램을 개발하려는 경우 테이블을 분할하는 것이 좋습니다.

(b) 데이터 수집의 다른 부분에 대해 다른 사람에게 다른 종류의 권한을 부여하려는 경우 분할하는 것이 더 편리 할 수 ​​있습니다. (물론 뷰를 정의하고 적절한 권한을 부여하는 방법을 살펴볼 수 있습니다.)

(c) 특히 개발 중에 데이터를 다른 위치로 이동하려면 테이블을 사용하여 파일 크기를 줄이는 것이 좋습니다.

(d) 더 작은 공간은 단일 엔티티의 특정 데이터 수집에 대한 애플리케이션을 개발하는 동안 편안함을 제공 할 수 있습니다.

(e) 가능성이 있습니다. 단일 값 데이터로 생각한 것이 미래에 실제로 여러 값이 될 수 있습니다. 예를 들어 신용 한도는 현재 단일 값 필드입니다. 그러나 내일 값을 (시작일, 종료일, 신용 값)으로 변경할 수 있습니다. 이제 분할 테이블이 유용 할 수 있습니다.

내 투표는 데이터가 적절하게 분할 된 여러 테이블에 대한 것입니다.

행운을 빕니다.


3
@RohitKhatri : 내가 아는 한 여러 테이블을 사용하면 대부분의 경우 성능이 향상됩니다.
Hari Harker

1
@HariHarker 귀하의 답변에 감사 드리지만 귀하의 액세스 패턴에 따라 다르다는 것을 알았습니다.
Rohit Khatri 2016 년

최근까지 저는 항상 모든 데이터를 하나의 테이블에 저장했지만 생각해 보면 성능 ​​(사용 사례에 따라 다름), 의미론 (일부 데이터는 다른 테이블) 및 개발. 예를 들어, 저는 지금 레거시 시스템 위에 맞춤형 ERP 시스템을 개발하고 있습니다. 추가 열로 이전 데이터베이스 테이블을 확장해야했습니다. 나는 새로운 데이터를 위해 새로운 테이블을 만들기로 결정했습니다. 일부 새로운 기능은 레거시 시스템에 유용하며 이제는 이전 쿼리를 너무 많이 다시 작성하지 않고도 쉽게 통합 할 수 있습니다
Ogier Schelvis

35

테이블 결합을 비정규 화라고합니다.

JOIN유지 관리 지옥을 만드는 대신 더 빠르게 실행 되도록 몇 가지 쿼리를 만드는 데 도움이 될 수도 있고 그렇지 않을 수도 있습니다 .

MySQL단지 사용 가능한 JOIN즉, 방법 NESTED LOOPS.

즉, 구동 테이블의 각 레코드 MySQL에 대해 루프의 구동 테이블에서 일치하는 레코드를 찾습니다.

레코드를 찾는 것은 순수한 레코드 스캔보다 수십 배가 걸릴 수있는 상당한 비용이 드는 작업입니다.

모든 레코드를 하나의 테이블로 이동하면이 작업을 제거하는 데 도움이되지만 테이블 자체가 커지고 테이블 스캔이 더 오래 걸립니다.

다른 테이블에 많은 레코드가있는 경우 테이블 스캔이 증가하면 순차적으로 스캔되는 레코드의 이점이 과중해질 수 있습니다.

반면에 유지 보수 지옥은 보장됩니다.


1
10000 명의 사용자가 있고 외래 키로 올바르게 설정된 데이터베이스와 조인을 수행하는 경우 select * from users where name = "bob"과 같은 작업을 수행하여 집중적 인 조회 만 필요합니다. bob이 있으면 인덱스를 사용하여 bob의 ID를 사용하고 있기 때문에 bob에 조인 된 테이블을 찾습니다. 이것은 쿼리에서 조인을 수행하거나 bob을 쿼리 한 다음 테이블을 별도로 쿼리하는지 여부에 관계없이 발생합니다. 물론 두 번째 쿼리는 bob의 ID를 기반으로하고 다른 것은 아닙니다.
루디 가르시아

17

모두 1 : 1 관계인가요? 즉, 사용자가 다른 사용자 레벨에 속할 수 있거나 사용자 관심사가 사용자 관심 테이블에서 여러 레코드로 표시되는 경우 해당 테이블을 병합하는 것은 즉시 문제가되지 않습니다.

정규화에 대한 이전 답변에 대해서는 데이터베이스 정규화 규칙이 성능을 완전히 무시하고 깔끔한 데이터베이스 디자인이 무엇인지 살펴보고 있다고 말해야합니다. 그것은 종종 당신이 성취하고자하는 것이지만, 성능을 추구하기 위해 적극적으로 비정규 화하는 것이 합리적 일 때가 있습니다.

대체로 질문은 테이블에있는 필드의 수와 액세스 빈도에 달려 있습니다. 사용자 활동이 종종 그다지 흥미롭지 않은 경우 성능 유지 관리상의 이유로 항상 동일한 기록에 보관하는 것이 성가신 일이 될 수 있습니다 . 예를 들어 설정과 같은 일부 데이터가 자주 액세스되지만 단순히 필드가 너무 많은 경우 테이블을 병합하는 것도 편리하지 않을 수 있습니다. 성능 향상에만 관심이있는 경우 설정을 별도로 유지하고 데이터베이스를 자주 쿼리 할 필요가 없도록 자체 세션 변수에 저장하는 등의 다른 접근 방식을 고려할 수 있습니다.


정규화는 깔끔함에 초점을 맞추고 성능을 완전히 무시한다는 귀하의 의견에 완전히 동의하지 않습니다. 두 시나리오 모두 상충 관계가 있으며 비정규 화는 실제로 데이터 무결성을 위험에 빠뜨립니다. 데이터베이스의 정규화는 비정규 화 된 테이블에서 무시할 수있는 빠른 성능 향상을 가져 오는 대신 실제로 데이터베이스의 전체 성능을 향상 시킨다고 말합니다.
루디 가르시아

토론이 특히 1 : 1 관계에 관한 것이므로 테이블 분할은 정규화 작업 이 아닙니다 . 중복 된 정보가 없으면 하나의 테이블이라도 정상입니다. (음, 3NF정규화를 충족하지 못할 수 있으므로 두 번째 테이블을 사용하여 문제를 해결하지만 OP가 다른 테이블에 대해 언급하는 것은 아닌 것 같습니다.)
ToolmakerSteve

14

수행 하는 모든 이들 테이블은 한 1-to-1관계는? 예를 들어 각 사용자 행에는 user_stats또는에 해당하는 행이 하나만 user_levels있습니까? 그렇다면 하나의 테이블로 결합하는 것이 합리적 일 수 있습니다. 그러나 관계 가 그렇지 않다면 1 to 1 그것들을 결합 (비정규 화)하는 것은 아마도 말이되지 않을 것입니다.

사용자 레코드가 수십만 또는 수백만 개가 아니라면 별도의 테이블과 하나의 테이블에 두는 것은 성능에 거의 영향을 미치지 않을 것입니다. 실제로 얻을 수있는 유일한 이점은 쿼리를 결합하여 쿼리를 단순화하는 것입니다.

ETA :

귀하의 경우 우려 하는 것에 대한 것입니다 너무 많은 열을 , 다음 생각 은 일반적으로 함께 사용하고 그 결합 물건 무엇을 (필요한 경우 또는 여러 개의 별도의 테이블) 별도의 테이블에 나머지를 떠나.

데이터를 사용하는 방식을 살펴보면 쿼리의 80 %가 해당 데이터의 20 %를 사용하고 나머지 80 %는 가끔씩 만 사용된다는 것을 알게 될 것입니다. 자주 사용하는 20 %를 하나의 테이블로 합치고, 자주 사용하지 않는 80 %는 별도의 테이블에 남겨두면 좋은 타협이있을 것입니다.


예, 각 테이블에는 각 사용자에 대해 하나의 행만 있습니다. 단순히 많은 중복 데이터를 관리해야하는 번거 로움을 덜기 위해. 이것이 내가 하나의 테이블이 적합하다고 생각하는 이유입니다. 사용자 데이터가 여러 행에 걸쳐있는 경우 해당 테이블이 기본 사용자 테이블과 분리 될 것으로 예상합니다.
Peter Craig

1
모든 테이블에 일대일 관계가 있으면 하나의 테이블을 사용하는 것이 더 쉬울 것입니다. 이 경우 테이블을 분할 할 필요가 없습니다. 테이블을 분할하면 행이 1 개 이상인 것으로 간주되어 다른 개발자가 이러한 방식으로 처리하는 경우가 발생할 수 있습니다.
Richard L

80/20을 데이터베이스 테이블 디자인에 적용하는 매우 흥미로운 생각. OOP (저는 주로 Java 개발자입니다) 클래스 디자인에 대해서도 생각하고 동일한 것이 효과적 일지 궁금합니다 (한 클래스에는 기본 80 % 애플리케이션 기능을 다른 클래스에는 나머지는 배치).
Zack Macomber

1
@ZackMacomber-아니요, 클래스 분할은 참조의 지역성을 기반으로해야합니다 . 여러 클래스로 분할 할 때의 이점은 더 작은 기능 단위 주위에 테두리를 그려서 이해 / 테스트 / 변경이 더 쉽고 해당 단위가 다른 기능 단위와 상호 작용하는 위치를 명확하게하는 것입니다. 목표는 대부분의 연결 (참조, 전화)를 유지하는 것입니다 내부에 몇 가지 연결을, 하나 개의 유닛 단위 사이 . 사용 사례마다 다른 인터페이스를 사용하여 클래스가 구현하는 여러 인터페이스 를 정의 하는 것은 이러한 분할을위한 유용한 첫 번째 단계가 될 수 있습니다.
ToolmakerSteve

@ToolmakerSteve 좋은의 생각 일
잭 컴버

9

하나의 대규모 테이블을 만드는 것은 관계형 데이터베이스 주체에 위배됩니다. 나는 그것들을 모두 하나의 테이블로 결합하지 않을 것입니다. 반복되는 데이터의 여러 인스턴스를 얻을 것입니다. 예를 들어 사용자에게 세 가지 관심사가있는 경우 세 가지 다른 관심사를 저장하기 위해 동일한 사용자 데이터가있는 3 개의 행이 있습니다. 다중 '정규화 된'테이블 접근 방식을 선택하십시오. 데이터베이스 정규화에 대해서는 Wiki 페이지를 참조하십시오 .

편집 : 귀하의 질문을 업데이트했기 때문에 내 답변을 업데이트했습니다 ... 이후로 더 지금 내 초기 답변에 동의합니다 ...

이 세포의 많은 부분이 비어있을 가능성이 있습니다.

예를 들어 사용자가 관심사가없는 경우 정규화하면 해당 사용자에 대한 관심 테이블에 행이 없습니다. 하나의 방대한 테이블에 모든 것이 있으면 NULL 만 포함하는 열 (그리고 분명히 많은 열)이 있습니다.

나는 수많은 테이블이있는 전화 통신 회사에서 일했으며 데이터를 얻으려면 많은 조인이 필요할 수 있습니다. 이러한 테이블에서 읽기 성능이 중요 할 때 보고서가 가리킬 수있는 조인, 계산 등이 필요없는 플랫 테이블 (예 : 비정규 화 된 테이블)을 생성 할 수있는 프로 시저가 생성되었습니다. 그런 다음 SQL 서버 에이전트와 함께 사용하여 특정 간격으로 작업을 실행합니다 (예 : 일부 통계의 주간보기는 일주일에 한 번 실행 됨).


비정규 화 된 데이터는 한 순간의 스냅 샷으로 일시적으로 만 존재하기 때문에이 접근 방식을 좋아합니다. 삽입 / 수정 / 삭제 문제가 없습니다. 완료되면 버리십시오.
ToolmakerSteve

7

모든 사람이 가지고있는 기본 사용자 정보가 포함 된 사용자 테이블을 만든 다음 기본적으로 사용자 ID와 관련된 모든 키, 값 쌍이 될 수있는 "user_meta"테이블을 추가하여 Wordpress가 수행하는 것과 동일한 접근 방식을 사용하면 안됩니다. 따라서 사용자에 대한 모든 메타 정보를 찾아야하는 경우 쿼리에 추가하면됩니다. 또한 로그인과 같은 작업에 필요하지 않은 경우 항상 추가 쿼리를 추가 할 필요는 없습니다.이 접근 방식의 이점은 사용자에게 Twitter 핸들 또는 각 개별 관심사를 저장하는 것과 같은 새로운 기능을 추가 할 수 있도록 테이블을 열어 둡니다. 또한 모든 메타 데이터를 지배하는 하나의 테이블이 있고이를 50 개가 아닌 하나의 연결로 제한하기 때문에 연결된 ID의 미로를 처리 할 필요가 없습니다.

Wordpress는 특히 플러그인을 통해 기능을 추가 할 수 있도록이 작업을 수행하므로 프로젝트의 확장 성을 높이고 새 기능을 추가해야하는 경우 완전한 데이터베이스 점검이 필요하지 않습니다.


Wordpress wp_usermeta테이블이 기하학적으로 확장됩니다. 각 사용자는 wp_usermeta해당 사용자에 대해 유지하려는 메타 정보의 각 부분에 대해 한 행씩 테이블에 X 행을 추가합니다 . 각 사용자에 대해 8 개의 사용자 정의 필드를 유지하면 wp_usermeta가 users * 8행 길이 가됨을 의미 합니다. 이로 인해 성능 문제가 발생하는 것 같지만 그게 문제인지 아닌지 잘 모르겠습니다…
thirdender

1
수만 명의 사용자가있는 경우 이것이 어떻게 성능 문제를 일으킬 수 있는지 알 수 있습니다. 기본적으로 데이터베이스는 사용자 메타 테이블에서 10000 * 8 개의 항목을 검색하여 원하는 항목을 찾아야합니다. 그러나 필요할 때만 메타 데이터를 쿼리하면 성능이 더 좋을 것이라고 생각합니다. 필요하지 않은 경우에도 항상 메타 데이터를 요청하는 경우 문제가있을 수 있습니다. 항상 메타 데이터가 필요한 경우 테이블을 분할하는 것이 최선의 방법이 아닐 수 있습니다.
Rudy Garcia

1
어제 우리 get_users()는 페이지 매김을 계산하기 위해 모든 사용자를로드하는 (을 사용하여 ) WP 테마를 처리했습니다 . SELECT COUNT(…)페이지 매김 쿼리를 대신 사용하도록 코드를 수정하면 페이지로드 시간이 28 초에서 약 400ms로 늘어났습니다. 성능이 조인 된 테이블 또는 단일 플랫 테이블과 어떻게 비교되는지 여전히 궁금합니다. 웹에서 성능 메트릭을 찾는 데 어려움이있었습니다.
thirdender

내 이전 의견을 생각하면 위의 페이지 매김 예제와 같은 어떤 이유로 든 모든 사용자를 선택해야하는 경우가 아니면 테이블을 분할하는 것이 여전히 효율적으로 보입니다. 모든 메타 정보를 검색하는 경우에도 usermeta 테이블에 80k 항목이 있습니다. 검색 할 내용이 많습니다. 아마도 누군가는 두 구현 모두에서 스크립트를 실행하여 더 나은 접근 방식을 테스트하고 평균을 얻기 위해 100 번 실행할 수있을 것입니다.
Rudy Garcia

1
나는 오늘 다시 이것을 읽고 10000 * 8 항목에 대한 내 의견이 사실이라는 것을 깨달았지만 데이터베이스가 작동하는 방식은 대부분 문제가되지 않습니다. 어떤 이유로 당신이 10000 명의 모든 사용자와 그들의 메타 정보를 잡는다면 이것은 우스꽝 스러울 것입니다. 나는 당신이 이것을 원하는 시나리오를 생각할 수 없습니다. 데이터베이스는 외래 키와 인덱싱 때문에 매우 빠른 속도로 단일 사용자의 메타를 쉽게 검색합니다. db 모델이 올바르게 설정되었다고 가정합니다.
Rudy Garcia

5

나는 이것이 그러한 "의존적"상황 중 하나라고 생각합니다. 여러 테이블을 갖는 것이 더 깨끗하고 이론적으로 더 좋습니다. 그러나 단일 사용자에 대한 정보를 얻기 위해 6-7 개의 테이블을 조인해야하는 경우 해당 접근 방식을 다시 생각하기 시작할 수 있습니다.


1

다른 테이블이 실제로 무엇을 의미하는지에 따라 다릅니다. user_details에 사용자가 1 명 이상 포함되어 있습니까? 요구 사항에 가장 적합한 정규화 수준은 요구 사항에 따라 다릅니다.

좋은 인덱스를 가진 테이블이 하나 있다면 아마도 더 빠를 것입니다. 그러나 다른 한편으로는 유지하기가 더 어려울 것입니다.

나에게 User_Details는 아마도 사용자와 1 : 1 관계이므로 건너 뛸 수있는 것처럼 보입니다. 하지만 나머지는 아마도 사용자 당 많은 행일까요?

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