2009-10-14 3 views
0

나는 세 개의 테이블이 있습니다몇 가지 JOINS (MySQL)을 수행하는 것보다 효율적인 방법이 있습니까?

  1. USER: user_id (pk); username
  2. FIELD: field_id (pk); name
  3. METADATA: metadata_id (pk); field_id (indx); user_id (indx); value

응용 프로그램이 사용자 정의 필드는 각 사용자에 대해 생성 할 수 있는지 이에 대한 추론입니다. 이처럼 보이는 끝나는 사용자 내가 (PHP를 통해) 동적 쿼리를 구축하고 모든 정보를 표시하려면 :

SELECT 
    u.username, m1.value AS m1value, m2.value AS m2value 
FROM user AS u 
LEFT JOIN metadata AS m1 
    ON (u.user_id=m1.user_id AND m1.field_id=1) 
LEFT JOIN metadata AS m2 
    ON (u.user_id=m2.user_id AND m2.field_id=2) 

이 예에서는 2 사용자 메타 데이터 필드를 가지고,하지만 당신은 아이디어를 얻을 어떤 방법이 것 12 개 필드가 있는지 살펴보십시오.

이 쿼리를 작성하는 또 다른 방법이 있습니까? 사용자 및 메타 데이터 필드가 커짐에 따라이 쿼리의 성능이 걱정됩니다.

편집 : 반환 된 결과에서 행당 한 명의 사용자를 보유하고 싶습니다.

답변

2

왜 모든 것을 한꺼번에 가져 가지 않을까요?

SELECT u.user_id,u.username, m.field_id,m.value FROM user u 
LEFT JOIN metadata m 
ON u.user_id=m.user_id 
WHERE 1 ORDER BY user_id 

또는 특정 사용자에 대한

:

색인을 넘어
SELECT u.user_id,u.username, m.field_id,m.value FROM user u 
LEFT JOIN metadata m 
ON u.user_id=m.user_id 
WHERE user_id = ? ORDER BY user_id 

의 USER_ID 정확히 두 테이블 사이의 동일한 유형 및 길이 확인, 또는 당신은 여전히 ​​테이블 스캔을하고 끝낸다.

귀하의 서버 코드는 어떤 언어입니까?

사용자 당 한 행 (일종의)을 얻는 간단한 방법은 행을 반환하는 루프에 있으며 마지막 행과 동일한 경우 각 user_id를 확인하십시오. 그렇지 않으면, 새로운 행.

while ($row = $sth->fetch_object()) { 
    $previous_user_id = ''; 
    if ($row->user_id != $previous_user_id) { 
    # new row 
    } else { 
    # not new row 
    } 
    $previous_user_id = $row->user_id; 
} 
+0

네,하지만 이상적으로 사용자 당 하나의 행을 반환하고 싶습니다. – Bart

+0

PHP/MYSQL은 서버 코드/db – Bart

+0

바트입니다.이 방법으로 반환하는 것이 더 빠를 수 있으며 응용 프로그램에서이를 피벗하게 할 수도 있습니다. 더 이상 동적으로 쿼리를 빌드 할 필요가 없습니다. 또한 동적 쿼리에 추가 할 사용자 정의 필드의 수를 파악하기 위해 미리 코드를 보내야 할 필요도 없습니다. – HLGEM

0

두 가지 쿼리가 필요합니다. 하나는 사용자 retrivial (SELECT * FROM users)이고 다른 하나는 사용자의 사용자 정의 필드를 가져옵니다 (SELECT * FROM fields WHERE users_id = user_id).

특정 경우에 하나의 쿼리로 해지 할 수는 있지만 결과가 정확히 무엇인지 나중에 알려주십시오.

0

당신은 일반적으로 같이 행 당 하나 개의 메타 데이터 요소를 반환 할 것 :

SELECT u.username, mi.field_id, m1.value 
FROM user AS u 
LEFT JOIN metadata AS m1 ON u.user_id = m1.user_id 

이가 수천 명의 사용자를 잘 수행해야합니다.

당신이 뭔가를 시도 할 수 있습니다
+0

함께 작업 할 계획 인 사용자의 수는 50,000 명입니다. 그리고 저는 6 개 정도의 메타 데이터 필드가있을 것이라고 추측합니다. – Bart

+0

여섯 개가있는 경우 해당 메타 데이터 필드를 주 사용자 테이블로 옮기지 않으시겠습니까? 그러면 디스크 공간이별로 없으며 특히 비어있는 경우 6 개의 필드가 훨씬 더 잘 수행됩니다. 빈 문자열이있는 varchar (4000)는 디스크에서 2 바이트를 차지합니다. – Andomar

0

...

SELECT 
    u.username, 
    (SELECT TOP 1 m.value 
    FROM metadata m 
    WHERE u.user_id=m.user_id AND m.field_id=1), 
    (SELECT TOP 1 m.value 
    FROM metadata m 
    WHERE u.user_id=m.user_id AND m.field_id=2) 
FROM user AS u 

...하지만 성능은 아마도 유사합니다 (악화 될 수있다) 당신이 무엇을. 성능 문제가있는 경우 user_id 및 field_id가 색인되어 있는지 확인하십시오.

+0

실적 메모를 잘 부탁드립니다. 감사. user_id-field_id의 고유 한 합성 키가 있습니다. – Bart

0

(의견 작성자가 지적했듯이, 이것은 MySQL에서는 유효하지 않으므로 죄송합니다.그러나 당신이 관심이있는 경우 :)

위와 같이 메타 데이터 테이블에 하나의 JOIN을 수행 한 다음 PIVOT을 사용하여 사용자 당 많은 행을 필드 당 하나씩 많은 행이있는 하나의 행으로 변경하십시오. 나는 이것이 SQL Server 2005 이상에서 유효하다고 생각합니다.

+0

불행히도 그는 MS SQL이 아닌 MySQL을 찾고 있습니다. –

관련 문제