Skip to content

Commit

Permalink
postgis: create one composite PRIMARY KEY instead of two indices
Browse files Browse the repository at this point in the history
Create a composite PRIMARY KEY for OSM ID and the unique `id` colum
(serial) instead of a separeate index for `id` and OSM ID. This can save
a few GB for large tables.

OSM ID is first, so lookups for diff imports are still fast. The `id`
makes the index unique as OSM IDs are not unique (e.g. multiple
mappings).
  • Loading branch information
olt committed May 10, 2019
1 parent 2d7f426 commit 5b0125c
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 4 deletions.
13 changes: 12 additions & 1 deletion database/postgis/postgis.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,13 @@ func (pg *PostGIS) Finish() error {
}

func createIndex(pg *PostGIS, tableName string, columns []ColumnSpec) error {
foundIDCol := false
for _, cs := range columns {
if cs.Name == "id" {
foundIDCol = true
}
}

for _, col := range columns {
if col.Type.Name() == "GEOMETRY" {
sql := fmt.Sprintf(`CREATE INDEX "%s_geom" ON "%s"."%s" USING GIST ("%s")`,
Expand All @@ -207,7 +214,11 @@ func createIndex(pg *PostGIS, tableName string, columns []ColumnSpec) error {
return err
}
}
if col.FieldType.Name == "id" {
if col.FieldType.Name == "id" && foundIDCol {
// Create index for OSM ID required for diff updates, but only if
// the table does have an `id` column.
// The explicit `id` column prevented the creation of our composite
// PRIMARY KEY index of id (serial) and OSM ID.
sql := fmt.Sprintf(`CREATE INDEX "%s_%s_idx" ON "%s"."%s" USING BTREE ("%s")`,
tableName, col.Name, pg.Config.ImportSchema, tableName, col.Name)
step := log.Step(fmt.Sprintf("Creating OSM id index on %s", tableName))
Expand Down
16 changes: 13 additions & 3 deletions database/postgis/spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,21 @@ func (col *ColumnSpec) AsSQL() string {

func (spec *TableSpec) CreateTableSQL() string {
foundIDCol := false
pkCols := []string{}
for _, cs := range spec.Columns {
if cs.Name == "id" {
foundIDCol = true
}
if cs.FieldType.Name == "id" {
pkCols = append(pkCols, cs.Name)
}
}

cols := []string{}
if !foundIDCol {
// only add id column if there is no id configured
// TODO allow to disable id column?
cols = append(cols, "id SERIAL PRIMARY KEY")
// Create explicit id column only if there is no id configured.
cols = append(cols, "id SERIAL")
pkCols = append(pkCols, "id")
}

for _, col := range spec.Columns {
Expand All @@ -62,6 +66,12 @@ func (spec *TableSpec) CreateTableSQL() string {
}
cols = append(cols, col.AsSQL())
}

// Make composite PRIMARY KEY of serial `id` and OSM ID. But only if the
// user did not provide a custom `id` colum which might not be unique.
if pkCols != nil && !foundIDCol {
cols = append(cols, `PRIMARY KEY ("`+strings.Join(pkCols, `", "`)+`")`)
}
columnSQL := strings.Join(cols, ",\n")
return fmt.Sprintf(`
CREATE TABLE IF NOT EXISTS "%s"."%s" (
Expand Down

0 comments on commit 5b0125c

Please sign in to comment.