何时在 PostgreSQL 中使用继承的表?

在哪些情况下应该使用继承的表?我试图非常简短地使用它们,继承在 OOP 世界中似乎并不常见。

我以为是这样的:

users具有所有用户级别所需的所有字段。表如 moderatorsadminsbloggers等,但字段是从父级检查的 没有。例如,users有电子邮件字段和继承 bloggers现在也有它,但它不是唯一的两个 usersbloggers在同一时间。也就是说。同样,我添加电子邮件字段到两个表。

我能想到的唯一用法是通常使用的字段,如 Row _ is _ delete创建 _ at已修改 _ at。这是继承表的唯一用法吗?

58911 次浏览

The only experience I have with inherited tables is in partitioning. It works fine, but it's not the most sophisticated and easy to use part of PostgreSQL.

Last week we were looking the same OOP issue, but we had too many problems with Hibernate - we didn't like our setup, so we didn't use inheritance in PostgreSQL.

There are some major reasons for using table inheritance in postgres.

Let's say, we have some tables needed for statistics, which are created and filled each month:

statistics
- statistics_2010_04 (inherits statistics)
- statistics_2010_05 (inherits statistics)

In this sample, we have 2.000.000 rows in each table. Each table has a CHECK constraint to make sure only data for the matching month gets stored in it.

So what makes the inheritance a cool feature - why is it cool to split the data?

  • PERFORMANCE: When selecting data, we SELECT * FROM statistics WHERE date BETWEEN x and Y, and Postgres only uses the tables, where it makes sense. Eg. SELECT * FROM statistics WHERE date BETWEEN '2010-04-01' AND '2010-04-15' only scans the table statistics_2010_04, all other tables won't get touched - fast!
  • Index size: We have no big fat table with a big fat index on column date. We have small tables per month, with small indexes - faster reads.
  • Maintenance: We can run vacuum full, reindex, cluster on each month table without locking all other data

For the correct use of table inheritance as a performance booster, look at the postgresql manual. You need to set CHECK constraints on each table to tell the database, on which key your data gets split (partitioned).

I make heavy use of table inheritance, especially when it comes to storing log data grouped by month. Hint: If you store data, which will never change (log data), create or indexes with CREATE INDEX ON () WITH(fillfactor=100); This means no space for updates will be reserved in the index - index is smaller on disk.

UPDATE: fillfactor default is 100, from http://www.postgresql.org/docs/9.1/static/sql-createtable.html:

The fillfactor for a table is a percentage between 10 and 100. 100 (complete packing) is the default

Inheritance can be used in an OOP paradigm as long as you do not need to create foreign keys on the parent table. By example, if you have an abstract class vehicle stored in a vehicle table and a table car that inherits from it, all cars will be visible in the vehicle table but a foreign key from a driver table on the vehicle table won't match theses records.

Inheritance can be also used as a partitionning tool. This is especially usefull when you have tables meant to be growing forever (log tables etc).

Main use of inheritance is for partitioning, but sometimes it's useful in other situations. In my database there are many tables differing only in a foreign key. My "abstract class" table "image" contains an "ID" (primary key for it must be in every table) and PostGIS 2.0 raster. Inherited tables such as "site_map" or "artifact_drawing" have a foreign key column ("site_name" text column for "site_map", "artifact_id" integer column for the "artifact_drawing" table etc.) and primary and foreign key constraints; the rest is inherited from the the "image" table. I suspect I might have to add a "description" column to all the image tables in the future, so this might save me quite a lot of work without making real issues (well, the database might run little slower).

EDIT: another good use: with two-table handling of unregistered users, other RDBMSs have problems with handling the two tables, but in PostgreSQL it is easy - just add ONLY when you are not interrested in data in the inherited "unregistered user" table.

"Table inheritance" means something different than "class inheritance" and they serve different purposes.

Postgres is all about data definitions. Sometimes really complex data definitions. OOP (in the common Java-colored sense of things) is about subordinating behaviors to data definitions in a single atomic structure. The purpose and meaning of the word "inheritance" is significantly different here.

In OOP land I might define (being very loose with syntax and semantics here):

import life


class Animal(life.Autonomous):
metabolism = biofunc(alive=True)


def die(self):
self.metabolism = False


class Mammal(Animal):
hair_color = color(foo=bar)


def gray(self, mate):
self.hair_color = age_effect('hair', self.age)


class Human(Mammal):
alcoholic = vice_boolean(baz=balls)

The tables for this might look like:

CREATE TABLE animal
(name       varchar(20) PRIMARY KEY,
metabolism boolean NOT NULL);


CREATE TABLE mammal
(hair_color  varchar(20) REFERENCES hair_color(code) NOT NULL,
PRIMARY KEY (name))
INHERITS (animal);


CREATE TABLE human
(alcoholic  boolean NOT NULL,
FOREIGN KEY (hair_color) REFERENCES hair_color(code),
PRIMARY KEY (name))
INHERITS (mammal);

But where are the behaviors? They don't fit anywhere. This is not the purpose of "objects" as they are discussed in the database world, because databases are concerned with data, not procedural code. You could write functions in the database to do calculations for you (often a very good idea, but not really something that fits this case) but functions are not the same thing as methods -- methods as understood in the form of OOP you are talking about are deliberately less flexible.

There is one more thing to point out about inheritance as a schematic device: As of Postgres 9.2 there is no way to reference a foreign key constraint across all of the partitions/table family members at once. You can write checks to do this or get around it another way, but its not a built-in feature (it comes down to issues with complex indexing, really, and nobody has written the bits necessary to make that automatic). Instead of using table inheritance for this purpose, often a better match in the database for object inheritance is to make schematic extensions to tables. Something like this:

CREATE TABLE animal
(name       varchar(20) PRIMARY KEY,
ilk        varchar(20) REFERENCES animal_ilk NOT NULL,
metabolism boolean NOT NULL);


CREATE TABLE mammal
(animal      varchar(20) REFERENCES animal PRIMARY KEY,
ilk         varchar(20) REFERENCES mammal_ilk NOT NULL,
hair_color  varchar(20) REFERENCES hair_color(code) NOT NULL);




CREATE TABLE human
(mammal     varchar(20) REFERENCES mammal PRIMARY KEY,
alcoholic  boolean NOT NULL);

Now we have a canonical reference for the instance of the animal that we can reliably use as a foreign key reference, and we have an "ilk" column that references a table of xxx_ilk definitions which points to the "next" table of extended data (or indicates there is none if the ilk is the generic type itself). Writing table functions, views, etc. against this sort of schema is so easy that most ORM frameworks do exactly this sort of thing in the background when you resort to OOP-style class inheritance to create families of object types.

Use it as little as possible. And that usually means never, it boiling down to a way of creating structures that violate the relational model, for instance by breaking the information principle and by creating bags instead of relations.

Instead, use table partitioning combined with proper relational modelling, including further normal forms.

I use inheritance when I have more than 1 on 1 relationships between tables.

Example: suppose you want to store object map locations with attributes x, y, rotation, scale.

Now suppose you have several different kinds of objects to display on the map and each object has its own map location parameters, and map parameters are never reused.

In these cases table inheritance would be quite useful to avoid having to maintain unnormalised tables or having to create location id’s and cross referencing it to other tables.