Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1tnK4D-004Et5-AN for pgsql-performance@arkaria.postgresql.org; Wed, 26 Feb 2025 16:15:25 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1tnK4C-008pWM-9d for pgsql-performance@arkaria.postgresql.org; Wed, 26 Feb 2025 16:15:24 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1tnK4B-008pVR-UL for pgsql-performance@lists.postgresql.org; Wed, 26 Feb 2025 16:15:23 +0000 Received: from mail-ej1-x632.google.com ([2a00:1450:4864:20::632]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.96) (envelope-from ) id 1tnK48-000DN8-2j for pgsql-performance@lists.postgresql.org; Wed, 26 Feb 2025 16:15:23 +0000 Received: by mail-ej1-x632.google.com with SMTP id a640c23a62f3a-abb8045c3f3so863627066b.2 for ; Wed, 26 Feb 2025 08:15:21 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cybertec.at; s=google; t=1740586520; x=1741191320; darn=lists.postgresql.org; h=mime-version:user-agent:content-transfer-encoding:references :in-reply-to:date:to:from:subject:message-id:from:to:cc:subject:date :message-id:reply-to; bh=17rP3AO4Ob8WG1Zz0esLP1csM2ICPeQn/lKvsbnkLpQ=; b=XiozLEQXbU9EaX02hNzYBFqPJmn5uRJGO/OyQfJNRjo31Rwqz3iKK+RttgmZ1Q9WDY 02VTC2UYKucNvKbJl3FADKXE+dDuSOFOO2udJlq+5mm/BTHMuH9RhrnV1p2hCO4jAyJ/ RgpV0n/H8J6wcTUwh7RPc7uWo9i496FY97JCD+ZS8pXadK9tMwn6IHXrqJH0seerzZ4N UFoPzx4hsZZ6wdBKSWFsbkyfOlEPqEKYqAfclyblRrdzOWlSDR3Wgey375HGPAd4ehQP DwGSeeiNxAo9tmtl3XaLhu+e8ZH41NPAFY6YX+earF/f7LCMA9xACRDBuJxkW687Pm9C V57g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1740586520; x=1741191320; h=mime-version:user-agent:content-transfer-encoding:references :in-reply-to:date:to:from:subject:message-id:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=17rP3AO4Ob8WG1Zz0esLP1csM2ICPeQn/lKvsbnkLpQ=; b=LdxOQ+Y00lkla6s3BLjpXUsk5hrp4gNfKsiVOba3Glp1e/4Nw+lXrW6i0OTDCgVNKb 4cRSPlvUtwXiQNs9yOBy9MMk1xdzR+KkEzCj8+bNkB+rnHEfiBq5W776yEg9+IMNEi6n Xo1dwnwzVVXuBmlqxtCO1qImSBrM8Pqp8LUDZJm1+lGrjHz8b14FUPAqfMj4n8hGIhPA h3MZ0DeQqvWJ7iWqQJmTUMqwQMGSMzqzYHQ4Rl0Ptnqou4ELE0jCjWQr/FH8pmCTs+yZ X8GxXaDjOt9+asMry5pZAKWlMZ+KLVYk05zM/oI0KBJXYmMiLAJJnoTvu101R8W+RkA8 NtQQ== X-Forwarded-Encrypted: i=1; AJvYcCWplPQj0Tdc69u8UAyqVhaaUH3xRqLmbkAw5kNYRDvZueYXbsPe7ZNGct1WFeYwSrQy1y3gLTJ0GpTyGaXw1jphzw==@lists.postgresql.org X-Gm-Message-State: AOJu0YxlJ6R5z9bGexZyOzNgh+FsiO4gvOUmLsB4TP4VXmht5i7T3kJ9 0TTdnStQqObco9/rWITktFAHPmS/tdSEQJ2zSktZSjrBQaeEdZqCU9Z/J16wfDG7y8rkikYPxKr bsq1NxA== X-Gm-Gg: ASbGncvHt+Ir6elXwtjw6kwWA8EPcDJsK8M6Q/4FH8cyxMZ/UaOIL6KKMtfAJTMf5mX 1rYm8YyVS7/J8mV5M2cmpPSJzKt2xdKKNHH/kpjABLflehEqTCLzkkGVbfGIxCHNwkpwfVIQv8b N7BI/LcawnVjDh2t0uUgY8FBDV8tMVS/hsxW21asqe+QLJFxf1ajqPYwGNW/HRU48vVvI2MMmfI DwqoHwYJPd9yPilLvuvEirlKPKn/xz8L0rEoyj77dpSsDVkwsH2bK/gDFXQGzXrLKaCq5ltQRgo Alb+MAqdZeJHpBlSl2a40noN1wbTGhTjNu5rZLU8J80= X-Google-Smtp-Source: AGHT+IGxzt6cI0ewATht9hzA3RG/+9E9nd3vGcE7Cje74rJNalZE2VcMy+gl806Mvsa/EJ3nis2gsg== X-Received: by 2002:a17:906:3110:b0:ab7:d537:91cb with SMTP id a640c23a62f3a-abeeed56795mr426355066b.7.1740586520309; Wed, 26 Feb 2025 08:15:20 -0800 (PST) Received: from localhost.localdomain ([41.66.99.220]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-abed2013586sm356844766b.108.2025.02.26.08.15.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 26 Feb 2025 08:15:19 -0800 (PST) Message-ID: <0bf497361892767b9e46df0928ed6554190ca1de.camel@cybertec.at> Subject: Re: Efficient pagination using multi-column cursors From: Laurenz Albe To: large.goose2829@salomvary.com, pgsql-performance@lists.postgresql.org Date: Wed, 26 Feb 2025 17:15:18 +0100 In-Reply-To: References: Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable User-Agent: Evolution 3.54.3 (3.54.3-1.fc41) MIME-Version: 1.0 List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk On Wed, 2025-02-26 at 15:27 +0100, large.goose2829@salomvary.com wrote: > I am working on optimizing a query that attempts to efficiently paginate > through a large table using multi-column "cursors" aka. the "seek method" > (as described in detail here: > https://use-the-index-luke.com/sql/partial-results/fetch-next-page). >=20 > The table (drastically simplified) looks like this: >=20 > CREATE TABLE data > ( > =C2=A0=C2=A0=C2=A0 col_1=C2=A0=C2=A0 int=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0 NOT NULL, > =C2=A0=C2=A0=C2=A0 col_2=C2=A0=C2=A0 int=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0 NOT NULL, > =C2=A0=C2=A0=C2=A0 col_3=C2=A0=C2=A0 int=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0 NOT NULL, > =C2=A0=C2=A0=C2=A0 content varchar(10) NOT NULL > ); >=20 > And has an appropriate index: >=20 > CREATE INDEX data_index ON data (col_1, col_2, col_3); >=20 > The recommended query to paginate through this table is using the "row va= lues" syntax: >=20 > SELECT content > FROM data > WHERE (col_1, col_2, col_3) > (10, 20, 29) > ORDER BY col_1, col_2, col_3 > LIMIT 100; >=20 > Which results in a perfectly optimized query plan >=20 > However, in reality, my query uses a mix of ascending and descending orde= ring (with an > index matching the order columns), in which case the=C2=A0WHERE (col_1, c= ol_2, col_3) > (10, 20, 29) > syntax is not an option (unless I somehow derive "reversed" data from the= column, > which I would like to avoid). Here are my ideas for this situation: https://www.cybertec-postgresql.com/en/keyset-pagination-with-descending-or= der/ Yours, Laurenz Albe