2009-10-14 34 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用戶的元數據字段,但你的想法是什麼如何做到這一點看看是否有一打田地。

是否有另一種更好的方法來編寫此查詢?隨着用戶和元數據字段的增長,我擔心此查詢的性能。

編輯: 我想在返回的結果中每行有一個用戶。

回答

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是完全相同的兩個表之間的相同類型和長度,或者你還是最終會做表掃描。

你的服務器代碼是什麼語言?

每個用戶(kinda)獲取一行的簡單方法是在循環中返回行,檢查每個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 2009-10-14 17:15:27

+0

PHP/MYSQL是服務器代碼/ db – Bart 2009-10-14 17:18:57

+0

Bart以這種方式返回它們可能會更快,然後讓應用程序轉換它們。您也不再需要動態構建查詢。您也不需要事先發送代碼來確定將多少個自定義字段添加到動態查詢中。 – HLGEM 2009-10-14 17:20:21

0

您將不得不有兩個查詢。一個用於用戶反悔(SELECT * FROM用戶),然後另一個用戶的自定義字段(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 2009-10-14 17:17:40

+0

如果您知道有六個,爲什麼不將這些元數據字段移動到主用戶表中?這會表現得更好,而6個字段的磁盤空間不多,特別是如果它們是空的。具有空字符串的varchar(4000)在磁盤上佔用2個字節。 – Andomar 2009-10-14 20:22:17

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 2009-10-14 17:19:54

0

(作爲評論者指出,這在MySQL中是無效的,所以,對不起。但如果你有興趣:)

做一個連接到元數據表按照以上建議,然後用PIVOT改變每位使用者多行到一行包含多列,每場一個。我認爲這在SQL Server 2005及更高版本中是有效的。

+0

不幸的是,他正在尋找MySQL而不是MS SQL – 2009-10-14 18:17:36

相關問題