2009-06-08 12 views
0

나는이 같은 두 개의 테이블이 있습니다이 표를 정규화하는 것이 더 빠릅니까?

표 사람 :
VARCHAR 이름
INTEGER 나이

표 메시지
VARCHAR 메시지
VARCHAR 이름

있습니다 삽입물의 수백 다음과 같은 검색어를 사용하여 Message 테이블에서 계속 삭제 :

insert into Message VALUES ('Hello there', 'John'); 
delete from Message where name = 'John'; 

사람들에게 ID 필드를 추가하고 사용자를 메시지의 ID로 참조하는 것이 좋습니다. 다음 쿼리가 훨씬 빨라 집니까?

FIRST - select id from User where name = 'John' 
THEN - delete from Message where id = $id 

처음에는 문자를 검색하는 것보다 ID를 검색하여 삽입 및 삭제가 더 빠르다고 생각했습니다. 그러나 얼마나 빨랐습니까? 속도를 늘리면 성능 조회에서 ID를 찾기 위해 추가 쿼리가 User 테이블에 필요하지 않게됩니까?

+0

클라이언트 코드가 데이터베이스 서버로부터 먼 경우에는 SELECT + DELETE가 상당히 비쌉니다. 클라이언트 코드와 데이터베이스 서버가 함께 배치되면 다소 비용이 많이 듭니다. 하나의 명령문 (아마도 WHERE Name = 'John'이라는 SELECT ID에서 ID = WHERE)을 삭제하면 더 효율적입니다. 최적화 프로그램에 최적화 할 부분을 지정하면 불가사의가 발생합니다. 벙어리 파일 관리자처럼 취급하면 성능이 저하 될 수 있습니다. –

답변

5

여기를 참조하십시오 그것과는 약간 느린

하지만 일이 (물론 이름의 길이, 데이터베이스 유형 등에 대한 의존성이 있습니다) 사용자가 자신의 이름을 변경할 때, 사용자를 삭제할 때 등? 그런 종류의 디자인은 당신에게 많은 고통을 줄 것입니다. 이 작은 성능 문제에 관계없이 정상화하는 것이 더 좋습니다.

+0

+1은 "속도가 전부는 아니지만"사운드 디자인은 실제로 장기적으로 보상합니다! –

1

대부분의 이름이 짧고 (15-20 문자가 아님) 표가 올바르게 색인화되어 있으면 ID 필드에서받는 속도 성능은 무시할 수 있습니다.

3

더 빠릅니까? 그러나 프로파일 링 만 말해줍니다. . .

id 문자열을 Person에 넣고 Message에서 Person 키로 외래 키 제약 조건을 넣는 것이 더 좋습니다 (모든 메시지가 Person 테이블의 사람들에게만 전달 될 수 있다고 가정 함).

당신은 여전히 ​​하나 개의 문장

delete from Message where id IN (select id from Person where Name = 'John') 

데이터베이스가이 최적화에 메시지를 삭제할 수 있습니다

은 그래서

(선택 & 삭제 계산서에 비해 즉, 빠르게) 두 개의 문보다 훨씬 빠르다 당신 사람을 삭제할 때 그 사람에게 보내는 모든 메시지도 자동으로 삭제되도록 외부 키 제한 조건에 계단식 삭제를 지정할 수 있습니다. 당신이 말했듯이

은 추가 쿼리 것보다에 Foreign Keys

+0

"id = (...)"는 "id IN (...)"이어야한다고 생각하지만, 사용중인 SQL의 특성에 따라 달라질 수 있습니다. –

+0

@Carl : 좋은 지적 –

1

추가 쿼리를 수행 할 필요가 없습니다. 다음과 같이 할 수 있습니다.

DELETE FROM Message 
INNER JOIN User 
    ON Message.id = User.id 
WHERE User.name = 'John' 
+0

그는 SQL Server를 사용하는 경우 Microsoft의 spiffy 이중 FROM 구문을 제거해야합니다. –

+0

이 참여는 공연에 큰 영향을 미칩니 까? – erotsppa

4

이름이 고유하지 않으므로 사람의 이름은 결코 좋은 기본 키가 아닙니다. 그리고 그들은 시간이 지남에 따라 변합니다. FAr은 대용 키를 사용하는 것이 좋습니다 (예 : Int에서 조인하는 것이 더 빠르며 더 느린 하위 쿼리를 사용하지 않는 많은 데이터베이스에서 삭제 작업에 참여할 수 있습니다). 특히 이름이 몇자를 초과하는 경향이 있기 때문에 더욱 그렇습니다.

+0

포인트가 있지만 데이터베이스가 고유성을 적용하는 경우 이름은 고유 할 수 있습니다 (예 : 여기에있는 "이름"은 출생 이름이 아닌 로그인 이름 일 수 있습니다. 이 질문은 스키마 디자인에 대해 자세히 설명하지는 않습니다. 아마 숫자 대 문자열에 의한 조회 성능에 더 관심이 있기 때문일 것입니다. –

1

내 경험에 의하면 웹 사이트 백엔드의 사용자 테이블은 거의 100 % 시간 동안 메모리에 남아있는 테이블 중 하나입니다. 모든 활동의 중심에 있으므로 페이지 버퍼에서 결코 벗어나지 않습니다. 그래서 나는 이와 같은 모든 참조에 대해 userId를 사용하는 길을 확실히 가고 싶습니다. 그런 작은 스키마와 정확한 질문에

1

는 테이블의 비정규이 빠를 것이다 원래 메시지의 내용을 덤프합니다. 쿼리 계획은 더 작고 최적화하기 쉬우 며 조인 오버 헤드가 없습니다.

일반적으로 훨씬 더 복잡합니다.

옳은 일은 질문입니다. 이를 위해서는 표준화 된 디자인으로 시작하지만 그렇게할만한 이유가 있다면 기꺼이 비정규화할 준비를하십시오. 일반적으로 정규화 된 데이터의 이득은 성능 손실을 상쇄하지만, 때때로 비정규 화에 대한 정당한 이유가 있습니다.

정규화 된 데이터는 유지하기가 쉽고 일반적으로 더 유연합니다. 유연성을 위해 숫자 키를 사용하면 같은 이름의 여러 사람을 가질 수 있습니다. 사람에 필드를 추가 할 수 있습니다. 모든 메시지을 검사하지 않고 시스템의 모든 사람을보기 위해 보고서를 실행하는 것이 더 쉽습니다.

그러나 성능에 영향을 줄 수 있습니다. 두 테이블에있는 데이터를 감안할 때 데이터베이스에는 조인 방법에 대한 몇 가지 옵션이 있습니다. 사람들 또는 메시지 중 하나를 기본 테이블로 사용할 수 있으며 조인이 수행되는 방식 (중첩 된 루프, 해시 조인, 정렬/병합 등)에 영향을줍니다.

하지만 정상적으로 실제로는 일 수 있습니다.입니다. 스키마가 설명하는 것보다 더 복잡하다면 어떨까요? 사람 테이블에 HR 관련 필드가 50 개 있고 메시지 테이블에 하나의 20 자 메시지 필드 만 있다고 가정 해 보겠습니다. 두 사람의 메시지가 있지만 100k 개의 메시지가있는 경우 비정규 화 된 메시지가 실제로 더 빠릅니다. 이것은 I/O가 데이터베이스의 가장 큰 제한 요소이기 때문입니다. 모든 데이터를 하나의 쿼리에 덤프 할 경우 정규화 된 데이터는 50 개의 필드를 한 번만 가져오고 메시지 테이블은 데이터로 밀집하게 채워집니다. 비정규 화 된 버전에서 메시지의 각 행에는 51 개의 필드가 포함되며 동일한 결과를 얻으려면 I/O 수를 대폭 늘릴 것입니다.

0

좋은 디자인을 얻을 때까지 최적화에 대해 걱정할 필요가 없습니다.

는 지금, 나는이 비현실적인 장난감 문제이지만, 일반적으로, 기본 키와 마음에 외래 키 관계를 설계하려는 경우 말을 열심히 생각하고,이 키가 될 매우 가능성 입니다 varchar.

GUID 일 수도 있고 int 일 수도 있지만 어느 쪽이든 적어도 클러스터되지 않은 인덱스 (클러스터 된 인덱스)를 가질 것이므로 비 클러스터형 인덱스를 가질 것입니다. - 클러스터 된 인덱스를 사용자 이름과 같이 사용하므로 궁극적으로 전체 테이블 시스템의 성능은이 테이블에 대한 견고한 정규화 된 디자인과 올바른 인덱싱 전략에 따라 결정됩니다.

+0

-1 대부분의 조회 테이블에는 FK를 통해 참조되는 VARCHAR 열에 PK가 있습니다. – onedaywhen

+0

내 조회 테이블의 대다수는 int surrrogates 또는 char 열이고 네, 일부 조회 테이블에는 varchar가 있습니다. 대부분의 응용 프로그램 엔티티 (즉, 자연 키가 없음)에 대해 varchar 기본 키를 가질 가능성이 거의 없다고 주장합니다. –

+0

"자연 키 없음"은 너무 먼 가정입니다. – onedaywhen

4

People.Name에 고유 제한 조건이 있고 Message.Name과 People.Name 사이에 참조 무결성 제한 조건이 있다고 가정하면 설계가 으로 이미으로 정규화되어 있습니다.

정규화의 문제는 아닙니다. 사람들이 이름을 변경할 수있게하려는 경우 성능 및 확장 성 문제가 있습니다 (메시지 테이블의 모든 관련 행을 업데이트해야 함).

사람들이 시스템에서 이름을 변경하지 않으면 문제가되지 않습니다. 이 경우 Name은 ID만큼이나 훌륭합니다. 일부 DBMS는 인덱스 문자열 (?) 대신 인덱스 번호를 사용하면 성능이 향상 될 수 있습니다.

삭제의 성능은 다른 문제입니다. 고유 한 이름이 이미있는 경우 이름으로 삭제하면 ID로 삭제하기 위해 조회 (또는 가입)를 수행하는 것보다 빠를 것이라고 말하고 싶지만 다시 당신 만의 벤치마킹을하고 싶습니다.

0

이는 모두 IO 및 유지 관리 가능성에 관한 것입니다. 정수가 아닌 varchar를 사용하면 varchar가 쿼리보다 4 바이트 미만인 경우 쿼리가 더 빠릅니다. 그러나 큰 개선은 아니며 이름을 변경해야 할 경우 많은 성능을 잃어 버리게됩니다! 메시지 테이블의 모든 행을 업데이트해야합니다 (예 : 삭제 및 삽입).

정수를 사용하는 경우 정수는 사용자 테이블에 대한 참조 용으로 4 바이트 만 저장됩니다. 그리고 사용자 테이블에서 ID와 이름에 커버 인덱스를 사용하면 생각할 수있는 약간의 오버 헤드 일뿐입니다. 사용자 테이블에 예상되는 행 수와 메모리 용량에 따라 사용자 테이블이 캐시에 남아있게됩니다. 이 경우보다 느린 물리적 스캔 대신 논리 스캔을 수행하게됩니다.

0

사이드 노트 : 테이블을 조인 할 열에 이미 인덱스가없는 경우 인덱스를 넣는 것을 잊지 마십시오.

관련 문제