PostgreSQL analog of SQL Server index(include columns)

PostgreSQL 11 supports included columns. Excerpt from Waiting for PostgreSQL 11 – Indexes with INCLUDE columns and their support in B-tree:

This patch introduces INCLUDE clause to index definition. This clause specifies a list of columns which will be included as a non-key part in the index. The INCLUDE columns exist solely to allow more queries to benefit from index-only scans. Also, such columns don't need to have appropriate operator classes. Expressions are not supported as INCLUDE columns since they cannot be used in index-only scans.

For now, only B-tree indexes support INCLUDE clause.

CREATE INDEX myindex ON mytablename (col1,col2) INCLUDE (col3,col4); 

EDIT:

CREATE INDEX:

[ INCLUDE ( column_name [, ...] ) ]

The optional INCLUDE clause specifies a list of columns which will be included in the index as non-key columns. A non-key column cannot be used in an index scan search qualification, and it is disregarded for purposes of any uniqueness or exclusion constraint enforced by the index. However, an index-only scan can return the contents of non-key columns without having to visit the index's table, since they are available directly from the index entry. Thus, addition of non-key columns allows index-only scans to be used for queries that otherwise could not use them.

Columns listed in the INCLUDE clause don't need appropriate operator classes; the clause can include columns whose data types don't have operator classes defined for a given access method.

Expressions are not supported as included columns since they cannot be used in index-only scans.

Currently, only the B-tree index access method supports this feature. In B-tree indexes, the values of columns listed in the INCLUDE clause are included in leaf tuples which correspond to heap tuples, but are not included in upper-level index entries used for tree navigation.


CREATE INDEX myindex ON mytablename (co1l, col2, col3, col4)

PostgreSQL does not support clustered or covering indexes.

Update:

For this query, you'll need to create the suggested index indeed:

SELECT  this_.id as id0_0_,   
        this_.device_id as device2_0_0_,  
        this_.time_id as time3_0_0_,  
        this_.gps_detail_id as gps4_0_0_   
FROM    DataMessage this_   
WHERE   this_.time_id = 65536
        AND this_.device_id = 32768

CREATE INDEX ix_datamessage_time_device_id_detail ON datamessage (time_id, device_id, id, gps_detail_id)

However, your tables seem to be over-normalized to me.

You can keep year, month and day in a single INT field in your table. This will save you a join.

There might be the point of keeping DataMessage and GpsDetails in separate tables if either GpsDetails are rarely linked to the DataMessage (this is, gps_details_id is often set to NULL), or a GPS details record can be shared between multiple data messages.

It it's not, it will be better to move the GPS details into the data messages table.


Support for index-only scanning has now been added to the beta version of PostgreSQL. It means that if an index contains the columns requested in a query, it likely won't need to go to the underlying data. Index-only scanning happens automatically.

Index-only scanning is the main reason for using Included Columns. I don't think postgres (beta or otherwise) supports included columns, so the desired columns will need to be added to the end of the list of columns to index, instead.