我正在研究一個報告系統,允許用戶任意查詢一組事實表,限制每個事實表的多維表。我寫了一個查詢構建器類,它根據約束參數自動組裝所有正確的聯接和子查詢,並且一切按設計工作。報告查詢:加入多個事實表的最佳方式?
但是,我有一種感覺,我沒有生成最有效的查詢。在一組包含幾百萬條記錄的表上,這些查詢需要大約10秒鐘的時間才能運行,並且我希望在不到一秒的範圍內將它們記下來。我有一種感覺,如果我能擺脫子查詢,結果會更有效率。
與其向您展示我的實際架構(這更復雜),我將向您展示一個類似的示例,它不需要解釋我的整個應用程序和數據模型即可說明這一點。
想象一下,我有一個音樂會信息數據庫,包括藝術家和場地。用戶可以任意標記藝術家和場地。所以模式看起來像這樣:
concert
id
artist_id
venue_id
date
artist
id
name
venue
id
name
tag
id
name
artist_tag
artist_id
tag_id
venue_tag
venue_id
tag_id
很簡單。
現在,讓我們來查詢數據庫,瞭解所有在今天的一個月內發生的所有音樂會,所有具有'techno'和'trombone'標籤的藝術家都會在'cheap-beer'和'great-mosh - 坑'標籤。
我已經能夠想出這個樣子的最佳查詢:
SELECT
concert.id AS concert_id,
concert.date AS concert_date,
artist.id AS artist_id,
artist.name AS artist_name,
venue.id AS venue_id,
venue.name AS venue_name,
FROM
concert
INNER JOIN (
artist ON artist.id = concert.artist_id
) INNER JOIN (
venue ON venue.id = concert.venue_id
)
WHERE (
artist.id IN (
SELECT artist_id
FROM artist_tag
INNER JOIN tag AS a on (
a.id = artist_tag.tag_id
AND
a.name = 'techno'
) INNER JOIN tag AS b on (
b.id = artist_tag.tag_id
AND
b.name = 'trombone'
)
)
AND
venue.id IN (
SELECT venue_id
FROM venue_tag
INNER JOIN tag AS a on (
a.id = venue_tag.tag_id
AND
a.name = 'cheap-beer'
) INNER JOIN tag AS b on (
b.id = venue_tag.tag_id
AND
b.name = 'great-mosh-pits'
)
)
AND
concert.date BETWEEN NOW() AND (NOW() + INTERVAL 1 MONTH)
)
查詢工作,但我真的不喜歡那些多個子查詢。如果我完全可以使用JOIN邏輯來完成相同的邏輯,我有一種感覺,性能會大大提高。
在一個完美的世界中,我會使用一個真正的OLAP服務器。但我的客戶將部署到MySQL或MSSQL或Postgres,並且我無法保證兼容的OLAP引擎可用。所以我堅持使用一個具有星型模式的普通RDBMS。
不要太擔心這個例子的細節(我的真實應用與音樂無關,但它有多個事實表,與我在這裏展示的關係類似)。在這個模型中,'artist_tag'和'venue_tag'表充當事實表,其他所有內容都是維度。
在這個例子中,重要的是要注意,如果我只允許用戶約束單個artist_tag或venue_tag值,那麼查詢就更容易編寫。當我允許查詢包含AND邏輯時,它只會變得非常棘手,需要多個不同的標記。
所以,我的問題是:你知道什麼是針對多個事實表編寫高效查詢的最佳技術?
我覺得這裏的問題的關鍵是真的查詢的AND性質,而不是「多個事實表」。 (儘管它們相互複合。)下面給出的答案通過在HAVING子句中執行查詢的AND組件來解決這個問題,而不是需要多次連接到相同的事實表。 – MatBailie 2009-04-18 17:26:57
時間來標記爲已解決/關閉/ ... :) – 2010-08-11 13:05:04