To overtake the described result, this would probably be the easiest and fastest:
SELECT DISTINCT ON (devicename, objectid) * FROM tbl ORDER BY devicename, objectid, ts DESC;
Details and explanation in this related answer .
From your sample data, I concluded that you are going to delete large parts of the original table. Most likely, itβs faster to TRUNCATE table (or DROP and recreate it, since you have to add the surrogate column pk) and write the remaining rows. It will also provide you with a table of throne, an implicitly clustered (ordered) way that best suits your needs, and saves the work that VACUUM would have to do otherwise. And this is probably even faster:
I also highly recommend adding a primary surrogate key to your table, preferably a serial column.
BEGIN; CREATE TEMP TABLE tmp_tbl ON COMMIT DROP AS SELECT DISTINCT ON (devicename, objectid) * FROM tbl ORDER BY devicename, objectid, ts DESC; TRUNCATE tbl; ALTER TABLE tbl ADD column tbl_id serial PRIMARY KEY;
Do all this inside the transaction to make sure that you don't work halfway.
This is fast, while your setup for temp_buffers is large enough to hold a temporary table. In addition, the system will begin to replace data with the disk, and performance requires immersion. You can set temp_buffers only for the current session as follows:
SET temp_buffers = 1000MB;
Thus, you do not lose memory, which is usually not required for temp_buffers . Must be before the first use of temporary objects in the session. More info in this related answer .
In addition, since INSERT follows TRUNCATE within a transaction, it will be easy on Write Ahead Log - improved performance.
Consider CREATE TABLE AS for an alternative route:
The only drawback: you need an exclusive lock . This can be a problem in databases with a large simultaneous load.
Finally, never use timestamp as the name of a column. This is a reserved word in every SQL standard and type name in PostgreSQL. I renamed the column to ts , as you may have noticed.