2012-03-08 58 views
0

好的,前提。三個表,爲這項工作很簡單:sql性能 - 從多個表中提取時的查詢設計

table first: 
id, name 

table second: 
id, firstId, secondName 

table third 
id, thirdName, secondId 

我想在第三的是在第二個有一個關係到了一定的「第一」行ID一個ForeignKey到行所有行。

典型的SQL:

select t.id, s.id as secondId, t.thirdName, s.secondName from third t 
inner join second s on t.secondId=s.id where s.firstId = X 

因此,這裏是我的問題:

難道是更快的性能明智的,有在第三列,而不是直接的外鍵先?

table third: 
id, secondId, firstId, name 

所以,我反而可能使查詢:

select t.id, s.id as secondId, t.thirdName, s.secondName from third t 
inner join second s on t.secondId=s.id where t.firstId = X 

有沒有少加入,因爲我需要從「第二」的數據太多,但我會做的從第三位而不是第二位查找「firstId」。

只是好奇,如果任何人有任何輸入:)

+0

不,我不認爲這將是多大的差別,如果有的話。甚至可能會更慢。如果你要將'table3'加入'table1',跳過join到'table2',是的。 (向table3添加'firstId'將意味着設計更改,更改表2和3的主鍵和外鍵。) – 2012-03-08 11:49:23

+0

感謝您的回覆。那麼,前提是我需要來自table2的數據。關於設計變更,是的,從領域理論的角度來看,但是我只是從性能的角度來介紹「第三」中的「firstid」列,即重複信息。哦,我會保持它,因爲它是我猜:) – Mathias 2012-03-08 14:02:10

+0

這當然是一個替代考慮。表2:在'(id,firstid)'和表3:添加'firstid'並將FK改爲'FOREIGN KEY(secondid,firstid)REFERENCES table2(id,firstid)''上添加'UNIQUE'約束。化合物PK和FK使得連接在許多場合更容易。問題是某些DBMS無法處理組合鍵中的auto_increasing序列,許多ORM根本無法處理組合PK和FK。 – 2012-03-08 15:01:51

回答

1

假設第二種方式更快,如果你重新寫你的第一個查詢爲:

select t.id, s.id as secondId, t.thirdName, s.secondName from second s 
inner join third t on t.id=s.id where s.firstId = X 

注意second的交換和展示位置third。有了這個,您將看到與第二個示例完全相同的性能,但third表格將更小,因爲它沒有額外的冗餘字段。

要指出的不具有本領域的好處,它更容易指出什麼增加額外的冗餘字段會做性能:

  • 佔用更多的磁盤空間
  • 減慢任何表掃描,因爲行現在將稍微不再
  • 更新性能也將稍微慢
  • 等等...

雖然理論上,它這個整體聽起來非常多像一個不成熟的優化,你只能做這個IF現有查詢慢(甚至做的是我上面重寫時),在該點通過改善索引,你會得到更好的回報。

+0

啊,謝謝你,對,這將是基本上相同的問題,所以從理論上講,在表3中包括列是沒有意義的。顯然它也佔用了更多的硬盤空間,是的:)確保它過早,而我並沒有打算實際做到這一點 - 但你知道在你頭腦中有什麼東西時它是如何的! – Mathias 2012-03-08 14:08:59

0

找出來的最可靠的方法就是試試看。

但是,鑑於您需要連接到第二張表,我實際上預計它會慢一點,因爲您必須首先從表third中獲取所有記錄,然後將它們中的每一個鏈接到在second相應的記錄,而不是先取出second記錄,然後鏈接到third記錄 - 所以你會在第一個場景檢索2 * M * N個記錄,並且只(M + 1)* N的第二記錄。

當然,如果您不需要鏈接到second表,如果只訪問third表,查詢運行速度會快得多。

0

你提出的設計是不正確的。沒有什麼可以保證third.firstId匹配父行的second.firstId

正確性比性能更重要!


這就是說,你可能可以使用識別的關係,自然鍵(相對於非識別關係和代理鍵):

enter image description here

這是適當的,如果thirdName必須是唯一的自身,而只是從second表中的父行的背景下,和secondName確實ñ ot需要獨立於其自身,但僅限於first表的父行的上下文中。

在這種情況下,你能避免加入完全,仍然可以得到firstIdsecondNamethirdName

SELECT * 
FROM third 
WHERE firstId = X 

即使有其他領域,上面沒有顯示,你需要從second閱讀,在JOIN仍然會更快,因爲InnoDB clusters的數據,你更自然地遵循這個聚類。通過避免使用代理鍵,您可以避免使用昂貴的二級索引(請參閱this article中的「集羣的缺點」)。

你付出的代價是在每個連續的子表的增長逐步地「胖」。無論這是一個值得付出的代價,只有您可以通過對代表性數據量進行測量來確定。

+0

當然,我知道我打破了規範化隊友:)正如我所提到的,我只是在考慮性能問題,忽略了任何設計缺陷(在這種情況下顯而易見)。 – Mathias 2012-03-08 20:07:42