Received: from maia.hub.org (maia-2.hub.org [200.46.204.251]) by mail.postgresql.org (Postfix) with ESMTP id 96A5C63240D for ; Sun, 9 May 2010 03:54:06 -0300 (ADT) Received: from mail.postgresql.org ([200.46.204.86]) by maia.hub.org (mx1.hub.org [200.46.204.251]) (amavisd-maia, port 10024) with ESMTP id 61863-07 for ; Sun, 9 May 2010 06:53:58 +0000 (UTC) X-Greylist: from auto-whitelisted by SQLgrey-1.7.6 Received: from shrek.krogh.cc (2605ds1-ynoe.0.fullrate.dk [90.184.12.24]) by mail.postgresql.org (Postfix) with ESMTP id D4A39632224 for ; Sun, 9 May 2010 03:53:58 -0300 (ADT) Received: from localhost (localhost [127.0.0.1]) by shrek.krogh.cc (Postfix) with ESMTP id 3F8CA1DB0FC for ; Sun, 9 May 2010 08:53:56 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at shrek.krogh.cc Received: from shrek.krogh.cc ([127.0.0.1]) by localhost (shrek.krogh.cc [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id KyOdfzaW9n2g for ; Sun, 9 May 2010 08:53:52 +0200 (CEST) Received: from [90.184.13.151] (2605ds1-ynoe.2.fullrate.dk [90.184.13.151]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) (Authenticated sender: jesper@krogh.cc) by shrek.krogh.cc (Postfix) with ESMTPSA id CBC0A1DB9E9 for ; Sun, 9 May 2010 08:53:51 +0200 (CEST) Message-ID: <4BE65BFD.5080100@krogh.cc> Date: Sun, 09 May 2010 08:53:49 +0200 From: Jesper Krogh User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.9) Gecko/20100423 Thunderbird/3.0.4 MIME-Version: 1.0 To: pgsql-performance@postgresql.org Subject: Re: Ugh - bad plan with LIMIT in a complex SELECT, any way to fix this? References: <4BE5CB07.60508@denninger.net> In-Reply-To: <4BE5CB07.60508@denninger.net> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit X-Virus-Scanned: Maia Mailguard 1.0.1 X-Spam-Status: No, hits=-0.001 tagged_above=-10 required=5 tests=BAYES_20=-0.001 X-Spam-Level: X-Archive-Number: 201005/33 X-Sequence-Number: 38617 Overal comment.. Try reading hrough these old threads most of your problem is the same issue: http://article.gmane.org/gmane.comp.db.postgresql.performance/22395/match=gin http://thread.gmane.org/gmane.comp.db.postgresql.performance/22331/focus=22434 > Table "public.post" > Column | Type | > Modifiers > -----------+--------------------------+-------------------------------------------------------- > subject | text | > message | text | > inserted | timestamp with time zone | > modified | timestamp with time zone | > replied | timestamp with time zone | > ordinal | integer | not null default > nextval('post_ordinal_seq'::regclass) > > Indexes: > "post_pkey" PRIMARY KEY, btree (ordinal) > "idx_message" gin (to_tsvector('english'::text, message)) > "idx_subject" gin (to_tsvector('english'::text, subject)) > > There's a bunch of other stuff in the table and many more indices, plus > foreign references, but stripping the table down to JUST THIS shows the > problem. > > ticker=# explain analyze select * from post where to_tsvector('english', > message) @@ to_tsquery('violence') order by modified desc; > QUERY > PLAN > ----------------------------------------------------------------------------------------------------------------------------------- > Sort (cost=31795.16..31819.68 rows=9808 width=436) (actual > time=14.222..17.213 rows=3421 loops=1) > Sort Key: modified > Sort Method: quicksort Memory: 3358kB > -> Bitmap Heap Scan on post (cost=1418.95..31144.90 rows=9808 > width=436) (actual time=1.878..7.514 rows=3421 loops=1) > Recheck Cond: (to_tsvector('english'::text, message) @@ > to_tsquery('violence'::text)) > -> Bitmap Index Scan on idx_message (cost=0.00..1416.49 > rows=9808 width=0) (actual time=1.334..1.334 rows=3434 loops=1) > Index Cond: (to_tsvector('english'::text, message) @@ > to_tsquery('violence'::text)) > Total runtime: 20.547 ms > (8 rows) > > Ok, very nice. 20ms. I like that. > > Now lets limit the return to 100 items: > > ticker=# explain analyze select * from post where to_tsvector('english', > message) @@ to_tsquery('violence') order by modified desc limit 100; > > QUERY > PLAN > ---------------------------------------------------------------------------------------------------------------------------------------------------- > Limit (cost=0.00..5348.69 rows=100 width=436) (actual > time=198.047..2607.077 rows=100 loops=1) > -> Index Scan Backward using post_modified on post > (cost=0.00..524599.31 rows=9808 width=436) (actual > time=198.043..2606.864 rows=100 loops=1) > Filter: (to_tsvector('english'::text, message) @@ > to_tsquery('violence'::text)) > Total runtime: 2607.231 ms > (4 rows) > > Bad. Notice that the optimizer decided it was going to do an index scan > with an internal filter on it! That's BACKWARD; what I want is for the > planner to first execute the index scan on the GIN index, then order the > return and limit the returned data set. > > But it gets much worse - let's use something that's NOT in the message > base (the table in question has some ~2m rows by the way and consumes > several gigabytes on disk - anything that actually READS the table is > instant "bad news!") > The one problem is that the query-planner doesn't have any specific knowlege about the cost of the gin-index search. Thats mentioned in one of the above threads. The other problem is that the cost of "to_tsvector" and "ts_match_vq" are set way to conservative in the default installation. Bumping those up will increase your amount of correct plans, but it doesnt solve all of it since the above problem is also interferring. But try upping the cost of those two functions significantly. alter function ts_match_vq(tsvector,tsquery) cost 500 (upping the cost times 500 for that one). I've I've got it right it is "more in the correct ballpark" it more or less translates to "how much more expensive the function is compared to really simple operators"). Another thing you can do, that favours the running time of the queries using to_tsvector() is to specifically store the tsvector in the table and create an index on that. That will at run-time translate into fewer calls (0 to be precise) of to_tsvector and only costing the ts_match_vq at run-time. > Why is the planner "taking into consideration" the LIMIT (I know the > docs say it does) and choosing to sequentially scan a table of nearly 2 > million rows?! I don't see how that makes sense.... irrespective of the > query being LIMITed. > > If it matters setting enable_seqscan OFF does not impact the results. > No, because you end up in index-scans on non-gin indexes in that situtaion.. so turning seqscan off has no effect. -- Jesper > > >