Tenho a seguinte tabela:
CREATE TABLE transactions
(
id NUMERIC(20, 0) NOT NULL DEFAULT NEXTVAL('transactions_sequence') PRIMARY KEY,
transaction_date TIMESTAMP DEFAULT NULL NULL,
transaction_type VARCHAR(255) DEFAULT NULL NULL,
merchant_id VARCHAR(255) DEFAULT NULL NULL,
transaction_type VARCHAR(255) DEFAULT NULL NULL,
-- Some more columns here
);
e o seguinte índice:
CREATE INDEX transactions_merchant_id_idx ON transactions (merchant_id, transaction_type, transaction_date DESC, id) WHERE merchant_id IS NOT NULL;
Tenho as seguintes dúvidas:
SELECT id, transaction_date
FROM transactions
WHERE merchant_id = 'some_merchant_id'
AND transaction_type = 'a'
AND transaction_date >= '2025-01-01'
AND transaction_date < '2025-03-28'
ORDER BY transaction_date DESC
LIMIT 100
Essa consulta funciona perfeitamente e eu obtenho apenas uma varredura de índice:
Limit (cost=0.29..7.47 rows=1 width=13) (actual time=1.119..1.120 rows=0 loops=1)
-> Index Scan using transactions_transaction_type_idx on transactions (cost=0.29..7.47 rows=1 width=13) (actual time=1.118..1.118 rows=0 loops=1)
Index Cond: (((transaction_type)::text = 'a'::text) AND (transaction_date >= '2025-01-01 00:00:00'::timestamp without time zone) AND (transaction_date < '2025-03-28 00:00:00'::timestamp without time zone))
Filter: ((merchant_id)::text = 'some_merchant_id'::text)
Planning Time: 0.311 ms
Execution Time: 1.139 ms
No entanto, quando preciso de transaction_type
resultados independentes com:
SELECT id, transaction_date
FROM transactions
WHERE merchant_id = 'some_merchant_id'
AND transaction_date >= '2025-01-01'
AND transaction_date < '2025-03-28'
ORDER BY transaction_date DESC
LIMIT 100
Ainda recebo apenas a varredura de índice:
Limit (cost=38.08..38.19 rows=44 width=13) (actual time=0.108..0.115 rows=47 loops=1)
-> Sort (cost=38.08..38.19 rows=44 width=13) (actual time=0.107..0.110 rows=47 loops=1)
Sort Key: transaction_date DESC
Sort Method: quicksort Memory: 27kB
-> Index Only Scan using transactions_merchant_id_idx on transactions (cost=0.29..36.88 rows=44 width=13) (actual time=0.029..0.093 rows=47 loops=1)
Index Cond: ((merchant_id = 'some_merchant_id'::text) AND (transaction_date >= '2025-01-01 00:00:00'::timestamp without time zone) AND (transaction_date < '2025-03-28 00:00:00'::timestamp without time zone))
Heap Fetches: 0
Planning Time: 0.228 ms
Execution Time: 0.161 ms
Eu tenho uma lista de todos os valores potenciais de transaction_type, então inicialmente pensei que isso seria melhor:
SELECT id, transaction_date
FROM transactions
WHERE merchant_id = 'some_merchant_id'
AND transaction_type IN ('a', 'b', 'c', ...) -- all the potential values here
AND transaction_date >= '2025-01-01'
AND transaction_date < '2025-03-28'
ORDER BY transaction_date DESC
LIMIT 100
mas em vez disso, dependendo do número de valores na IN
cláusula, posso obter um adicional filter
no plano de consulta:
Limit (cost=38.29..38.40 rows=43 width=13) (actual time=0.110..0.118 rows=47 loops=1)
-> Sort (cost=38.29..38.40 rows=43 width=13) (actual time=0.109..0.112 rows=47 loops=1)
Sort Key: transaction_date DESC
Sort Method: quicksort Memory: 27kB
-> Index Only Scan using transactions_merchant_id_idx on transactions (cost=0.31..37.13 rows=43 width=13) (actual time=0.030..0.097 rows=47 loops=1)
Index Cond: ((merchant_id = 'some_merchant_id'::text) AND (transaction_date >= '2025-01-01 00:00:00'::timestamp without time zone) AND (transaction_date < '2025-03-28 00:00:00'::timestamp without time zone))
" Filter: ((transaction_type)::text = ANY ('{a,b,c,d,e,f}'::text[]))"
Heap Fetches: 0
Planning Time: 0.340 ms
Execution Time: 0.142 ms
Então, mesmo se eu pular a transaction_type
coluna do meio, meu índice é usado. Mas com qual consulta eu sou melhor, com IN
on transaction_type
com todos os valores potenciais ou sem nem mesmo o filtro? Como meu índice ainda é usado sem o filtro on transaction_type
?