【发布时间】:2009-11-05 20:30:07
【问题描述】:
这更像是一个通用的 SQL 问题,但如果有人知道 Firebird/Interbase 特定优化,我将使用 Firebird 2.5。首先,以下是一个简化的示例架构,用于说明我要解决的问题:
CREATE TABLE users
(
id INTEGER PRIMARY KEY,
name VARCHAR(16)
);
CREATE TABLE data_set
(
id INTEGER PRIMARY KEY,
name VARCHAR(64)
);
CREATE UNIQUE INDEX data_set_name_idx ON data_set(name);
CREATE TABLE data
(
user_id INTEGER,
data_set_id INTEGER,
data BLOB,
PRIMARY KEY(user_id, data_set_id)
);
CREATE INDEX data_user_id_idx ON data(user_id);
CREATE INDEX data_data_set_id_idx ON data(data_set_id);
我尝试运行的查询如下:
SELECT users.name, data_set.name, data FROM users, data_set, data
WHERE user_id=XXX AND user_id=users.id AND data_set_id=data_set.id
ORDER BY data_set.name;
用我想要的 user_id 填写“XXX”。所以我正在做的是从 data 表中选择特定用户拥有的所有行,并根据 data_set 名称对结果进行排序。
按原样工作,但问题是 data 表中有超过十亿行,而 data_set 表也不小。单个用户 ID 的结果集可能有数亿行。发生的情况是,为了使 ORDER BY 工作,数据库必须创建大量临时数据,这些数据非常慢并且使用大量磁盘空间。如果没有 ORDER BY,它会很快,但显然不像我需要的那样排序。
一种解决方案是获取 data_set.name 值并将它们放在 data 的 varchar 列中。然后可以将其编入索引并快速排序。这种方法的问题是它会有大量的重复数据并使数据库变得非常庞大。
另一种解决方案是索引视图或索引计算列。据我所知,Firebird 都不支持这些。
还有其他想法吗?
【问题讨论】:
-
我没有明确的答案,但我认为您可以更多地使用您的索引并使用查询对它们进行基准测试。
-
为什么要为单个用户提取“数亿行”?不仅处理查询而且将数据传输到客户端都需要时间。
-
@liggett78:哦,我同意传输它需要时间,因为它有很多数据。这就是为什么我要尽可能加快速度。它不需要那么慢,因为它浪费了大量时间为排序创建临时数据。
标签: sql foreign-keys query-optimization firebird firebird2.5