10

我有下表(PostgreSQL 8.3),其中存储了一些产品的价格。价格与另一个数据库同步,基本上下面的大多数字段(除了一个)都不是由我们的客户更新 - 而是每隔一段时间删除和刷新一次以与另一个股票数据库同步:

CREATE TABLE product_pricebands (
    template_sku varchar(20) NOT NULL,
    colourid integer REFERENCES colour (colourid) ON DELETE CASCADE,        
    currencyid integer NOT NULL REFERENCES currency (currencyid) ON DELETE CASCADE,
    siteid integer NOT NULL REFERENCES site (siteid) ON DELETE CASCADE,

    master_price numeric(10,2),

    my_custom_field boolean, 

    UNIQUE (template_sku, siteid, currencyid, colourid)
);

在同步时,我基本上删除了上面的大部分数据,除了数据 WHERE my_custom_field 为 TRUE (如果它是 TRUE,这意味着客户端通过他们的 CMS 更新了这个字段,因此这个记录不应该被删除)。然后我在表中插入 100 到 1000 行,并在插入失败的地方更新(即 (template_sku、siteid、currencyid、 colourid) 的组合已经存在的地方)。

我的问题是 - 这里应该应用什么最佳实践来创建主键?甚至需要主键吗?我想让主键 = (template_sku, siteid, currencyid, colourid) - 但是 colourid 字段可以为 NULL,并且在复合主键中使用它是不可能的。

从我在其他论坛帖子上看到的内容来看,我认为我已经正确地完成了上述操作,只需要澄清一下:

1)我是否应该使用“串行”主键以防万一我需要一个?目前我没有,也不认为我会,因为表中的重要数据是价格和我的自定义字段,仅由 (template_sku, siteid, currencyid, colourid) 组合标识。

2) 由于 (template_sku, siteid, currencyid, colourid) 是我将用来查询产品价格的组合,我是否应该在我的列中添加任何进一步的索引,例如“template_sku”,它是一个 varchar?还是 UNIQUE 约束已经是我的 SELECT 的一个很好的索引?

4

1 回答 1

12

我是否应该使用“串行”主键以防万一我需要一个?

如果需要,您可以稍后轻松添加序列列:

ALTER TABLE product_pricebands ADD COLUMN id serial;

该列将自动填充唯一值。您甚至可以在同一语句中将其设为主键(如果尚未定义主键):

ALTER TABLE product_pricebands ADD COLUMN id serial PRIMARY KEY;

如果您从其他表中引用该表,我建议您使用这样的代理主键,因为通过四列链接起来相当笨拙。在带有 JOIN 的 SELECT 中它也较慢。

无论哪种方式,您都应该定义一个主键。包含可为空列的 UNIQUE 索引不是完全替换。它允许包含 NULL 值的组合重复,因为两个 NULL 值永远不会被视为相同。这可能会导致麻烦。


作为

colourid 字段可以为 NULL

您可能想要创建两个唯一索引。该组合(template_sku, siteid, currencyid, colourid)不能是 a PRIMARY KEY,因为 nullable ,但是您可以像已经拥有的那样colourid创建约束(自动实现索引):UNIQUE

ALTER TABLE product_pricebands ADD CONSTRAINT product_pricebands_uni_idx
UNIQUE (template_sku, siteid, currencyid, colourid)

该索引完美地涵盖了您在 2) 中提到的查询。
如果您想避免“重复”,请另外创建一个部分唯一索引(colourid IS NULL)

CREATE UNIQUE INDEX product_pricebands_uni_null_idx
ON product_pricebands (template_sku, siteid, currencyid)
WHERE colourid IS NULL;

覆盖所有基地。我在 dba.SE的相关答案中写了更多关于该技术的内容。


上面的简单替代方法是使colouridNOT NULL 并创建一个主键而不是上面的product_pricebands_uni_idx


另外,正如你

基本上DELETE大部分数据

对于您的重新填充操作,删除在重新填充操作期间不需要的索引并在之后重新创建索引会更快。从头开始构建索引比增量添加所有行要快一个数量级。

您怎么知道使用(需要)哪些索引?

  • 使用 测试您的查询EXPLAIN ANALYZE
  • 或者使用内置的统计信息pgAdmin在单独的选项卡中显示所选对象的统计信息。

my_custom_field = TRUE将少数行选择到临时表、TRUNCATE基表中并重新插入幸存者也可能更快。取决于您是否定义了外键。看起来像这样:

CREATE TEMP TABLE pr_tmp AS
SELECT * FROM product_pricebands WHERE my_custom_field;

TRUNCATE product_pricebands;
INSERT INTO product_pricebands SELECT * FROM pr_tmp;

这避免了很多吸尘。

于 2012-05-09T14:32:37.390 回答