1

I am using postgress database (Version 9.5.4), I have a table structure like this,

create table test (
 id serial primary key,
 company_name varchar(255) not null,
 department varchar(255) not null,
 joined_date timestamp not null
);

Following are my exact queries (Only the below three not any other),

  1. Query 1

    SELECT *
    FROM test
    WHERE joined_date::date BETWEEN '2017-09-25' AND '2017-10-25'; 
    
  2. Query 2

    SELECT *
    FROM test
    WHERE joined_date::date BETWEEN '2017-09-25' AND '2017-10-25'
     AND company_name = 'xxx'; 
    
  3. Query 3

    SELECT *
    FROM test
    WHERE joined_date::date BETWEEN '2017-09-25' AND '2017-10-25'
     AND company_name = 'xxx'
     AND department = 'yyy';
    

I want to speed up my query execution time, I tried to add index some thing like this,

CREATE INDEX index_test ON test (joined_date, company_name, department);

After creating index, the query execution time doesn't have any improvement. On adding EXPLAIN keyword, I found the index is no longer used. But when adding equals condition instead of between keyword, index is being used. But my use case would be within date range and optional fields with equal condition. How to achieve my index use case with most efficient performance?

1
  • don't use varchar(255) in PostgreSQL, just use text. also, don't use timestamp use timestamp with time zone Commented Oct 25, 2017 at 21:43

1 Answer 1

1

Index will be used if you remove cast to date (joined_date instead of joined_date::date) from WHERE clause (upper bound in BETWEEN should be changed accordingly).

 select * 
 from test 
 where joined_date >= '2017-09-25' AND joined_date <'2017-10-26' ;

Alternatively , you can create index as CREATE INDEX index_test2 ON test (cast (joined_date as date), company_name, department);

Proof

CREATE TABLE test (
 id serial PRIMARY KEY,
 company_name varchar(255) not null,
 department varchar(255) not null,
 joined_date timestamp not null
);
INSERT INTO test(company_name, department,joined_date)
SELECT
 md5(x::text),
 CASE WHEN x%2 = 0 THEN 'foo' WHEN x%3 = 0 THEN 'bar' ELSE 'baz' END,
 now()
FROM generate_series(1,1e6)
 AS gs(x);
CREATE INDEX index_test
 ON test (joined_date, company_name, department);
VACUUM ANALYZE test;

Query 1

EXPLAIN ANALYZE SELECT *
FROM test
WHERE joined_date BETWEEN '2017-09-25' AND '2017-10-25'; 
 QUERY PLAN 
-------------------------------------------------------------------------------------------------------------------------------------------------------------
 Index Scan using index_test on test (cost=0.42..8.45 rows=1 width=49) (actual time=0.069..0.069 rows=0 loops=1)
 Index Cond: ((joined_date >= '2017-09-25 00:00:00'::timestamp without time zone) AND (joined_date <= '2017-10-25 00:00:00'::timestamp without time zone))
 Planning time: 0.142 ms
 Execution time: 0.097 ms
(4 rows)

Query 2

EXPLAIN ANALYZE SELECT *
FROM test
WHERE joined_date BETWEEN '2017-09-25' AND '2017-10-25'
 AND company_name = 'xxx'; 
 QUERY PLAN 
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Index Scan using index_test on test (cost=0.42..8.45 rows=1 width=49) (actual time=0.016..0.016 rows=0 loops=1)
 Index Cond: ((joined_date >= '2017-09-25 00:00:00'::timestamp without time zone) AND (joined_date <= '2017-10-25 00:00:00'::timestamp without time zone) AND ((company_name)::text = 'xxx'::text))
 Planning time: 0.111 ms
 Execution time: 0.047 ms
(4 rows)

Query 3

SELECT *
FROM test
WHERE joined_date BETWEEN '2017-09-25' AND '2017-10-25'
 AND company_name = 'xxx'
 AND department = 'yyy';
 QUERY PLAN 
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Index Scan using index_test on test (cost=0.42..6.20 rows=1 width=49) (actual time=0.017..0.017 rows=0 loops=1)
 Index Cond: ((joined_date >= '2017-09-25 00:00:00'::timestamp without time zone) AND (joined_date <= '2017-10-25 00:00:00'::timestamp without time zone) AND ((company_name)::text = 'xxx'::text) AND ((department)::text = 'yyy'::text))
 Planning time: 0.120 ms
 Execution time: 0.046 ms
(4 rows)
Evan Carroll
65.7k50 gold badges259 silver badges510 bronze badges
answered Oct 25, 2017 at 18:02
2
  • Still I don't see any improvements, also EXPLAIN shows me that index is not being used. Commented Oct 25, 2017 at 18:27
  • Show the result of the EXPLAIN Commented Oct 25, 2017 at 21:41

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.