我正在研究一个报告系统,允许用户任意查询一组事实表,限制每个事实表的多维表。我写了一个查询构建器类,它根据约束参数自动组装所有正确的联接和子查询,并且一切按设计工作。报告查询:加入多个事实表的最佳方式?
但是,我有一种感觉,我没有生成最有效的查询。在一组包含几百万条记录的表上,这些查询需要大约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