2

这更像是一个通用的 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_set名称对结果进行排序。

这可以正常工作,但问题是数据表中有超过十亿行,并且data_set表也不小。单个用户 id 的结果集可能有数亿行。发生的情况是,为了使 ORDER BY 工作,数据库必须创建大量临时数据,这些数据非常慢并且使用大量磁盘空间。如果没有 ORDER BY,它会很快,但显然不像我需要的那样排序。

一种解决方案是获取data_set.name值并将它们放在data的 varchar 列中。然后可以将其编入索引并快速排序。这种方法的问题是它会有大量的重复数据并使数据库绝对庞大。

另一种解决方案是索引视图或索引计算列。据我所知,Firebird 都不支持这些。

还有其他想法吗?

4

3 回答 3

1

这是相当投机的,但我想知道这是否可以重组为:

  1. 用户和数据集之间的笛卡尔积,包括关于用户的谓词。
  2. 按数据集名称排序
  3. 加入数据

... 会更有效,特别是如果您只对查询的前几行感兴趣。

在 Oracle 中,我认为这不会是因为嵌套循环连接的效率会比哈希连接低得多,但恐怕我根本不熟悉 firebird。

于 2009-11-03T14:16:28.190 回答
0

尝试在 data_set(id, name) 上定义一个索引并进行试验 - 可能与此处的其他建议结合使用。如果您的要求要求并且 Firebird 支持唯一约束,您可以将现有的 UNIQUE 索引更改为 UNIQUE CONSTRAINT。

于 2009-11-03T14:37:41.103 回答
0

为什么不索引 data_set.name?

此外,我会跳过事实表(数据)的主键定义,并为外键放置两个单独的索引,以加快连接速度。(当然,如果要插入大量记录,索引可能会对插入产生影响)

如果您需要确保事实表的唯一约束,您可以从将数据传输到该表的作业中完成(我没有关于该表的详细信息:)。

于 2009-11-03T12:14:43.363 回答