Received: from localhost (maia-4.hub.org [200.46.204.183]) by postgresql.org (Postfix) with ESMTP id 056659FB2C2 for ; Sat, 27 Jan 2007 19:35:09 -0400 (AST) Received: from postgresql.org ([200.46.204.71]) by localhost (mx1.hub.org [200.46.204.183]) (amavisd-new, port 10024) with ESMTP id 24920-07 for ; Sat, 27 Jan 2007 19:35:05 -0400 (AST) X-Greylist: from auto-whitelisted by SQLgrey-1.7.4 Received: from smtp104.sbc.mail.mud.yahoo.com (smtp104.sbc.mail.mud.yahoo.com [68.142.198.203]) by postgresql.org (Postfix) with SMTP id 510769FB27A for ; Sat, 27 Jan 2007 19:35:05 -0400 (AST) Received: (qmail 43145 invoked from network); 27 Jan 2007 23:34:59 -0000 Received: from unknown (HELO mail.hyperstep.com) (ryan.holmes@sbcglobal.net@69.235.84.249 with login) by smtp104.sbc.mail.mud.yahoo.com with SMTP; 27 Jan 2007 23:34:59 -0000 X-YMail-OSG: hfqsmPkVM1kbXmSJlXbXWdx9EcicJ.8CSXPfpjySIEB2Q14D0fk2EmPm42McaQi7C5J7xm4rlezpHY5XZBne8Yu61LYpp_nZbx4oX799B9Olnd7NwGOAqYYi_548wm0- Received: from [10.0.1.100] (unknown [10.0.1.100]) by mail.hyperstep.com (Postfix) with ESMTP id 702FF175C19 for ; Sat, 27 Jan 2007 15:34:58 -0800 (PST) Mime-Version: 1.0 (Apple Message framework v752.2) Content-Transfer-Encoding: 7bit Message-Id: Content-Type: text/plain; charset=US-ASCII; delsp=yes; format=flowed To: pgsql-performance@postgresql.org From: Ryan Holmes Subject: IN operator causes sequential scan (vs. multiple OR expressions) Date: Sat, 27 Jan 2007 15:34:56 -0800 X-Mailer: Apple Mail (2.752.2) X-Virus-Scanned: Maia Mailguard 1.0.1 X-Archive-Number: 200701/387 X-Sequence-Number: 22988 PostgreSQL version: 8.2.1 OS: Windows Server 2003 I have a relatively simple query where the planner chooses a sequential scan when using the IN operator but chooses an index scan when using logically equivalent multiple OR expressions. Here is the table structure and the two versions of the query: CREATE TABLE pool_sample ( id integer NOT NULL, state character varying(25) NOT NULL, not_pooled_reason character varying(25) NOT NULL, "comment" character varying(255), CONSTRAINT "pk_poolSample_id" PRIMARY KEY (id) ) WITHOUT OIDS; CREATE INDEX "idx_poolSample_state" ON pool_sample USING btree (state); The following query uses a sequential scan (i.e. filter) on the "state" column and takes about 5 seconds to execute (up to ~45 seconds with an "empty" cache): SELECT * FROM pool_sample ps WHERE ps.state IN ('PENDING_REPOOL_REVIEW', 'READY_FOR_REPOOL'); This version of the query uses an index scan on "state" and takes about 50 milliseconds: SELECT * FROM pool_sample ps WHERE ps.state = 'PENDING_REPOOL_REVIEW' OR ps.state = 'READY_FOR_REPOOL'; There are over 10 million rows in the pool_sample table and 518 rows meet the given criteria. In the first query, the planner estimates that nearly 10 million rows will be returned (i.e. almost all rows in the table). In the second query, the planner estimates 6830 rows, which seems close enough for the purposes of planning. If I explicitly cast the state column to text, the IN query uses an index scan and performs just as well as the multiple OR version: SELECT * FROM pool_sample ps WHERE ps.state::text IN ('PENDING_REPOOL_REVIEW', 'READY_FOR_REPOOL'); So it would appear that the planner automatically casts the state column to text within an OR expression but does not perform the cast in an IN expression. Our SQL is generated from an O/R mapper, so it's non-trivial (or at least undesirable) to hand tune every query like this with an explicit type cast. The only option I've come up with is to define the state column as text in the first place, thus avoiding the need to cast. Would this work? Are there any other/better options? Thanks, -Ryan