Received: from maia.hub.org (unknown [200.46.208.211]) by mail.postgresql.org (Postfix) with ESMTP id 28FCE633AE1 for ; Fri, 5 Feb 2010 07:17:15 -0400 (AST) Received: from mail.postgresql.org ([200.46.204.86]) by maia.hub.org (mx1.hub.org [200.46.208.211]) (amavisd-maia, port 10024) with ESMTP id 37690-06 for ; Fri, 5 Feb 2010 11:16:58 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from ey-out-2122.google.com (ey-out-2122.google.com [74.125.78.24]) by mail.postgresql.org (Postfix) with ESMTP id CA9AC63432C for ; Fri, 5 Feb 2010 07:17:03 -0400 (AST) Received: by ey-out-2122.google.com with SMTP id 9so685770eyd.33 for ; Fri, 05 Feb 2010 03:17:01 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:message-id:date:from :user-agent:mime-version:to:cc:subject:references:in-reply-to :content-type:content-transfer-encoding; bh=b4D4ALTyhpjR8nOjx4bJHCgmtaFt3Szja3wb9Sa5RRE=; b=UlZBMxKXEOKLFmU7LhTzTG1uFp12E51SOfUydvvQ/8JNlKu5rsOtavtSBqbDL4WLiZ fE2WYkAmbxo0GfqpT5TTA5HEajPnQ+JkgM/6nrh8R3QV5eTUqJ9NkYYUPfSkVvA9pdaQ TQWtVFY0nUCcCjbaGmNsAiNasHmH74zP8LJLE= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=message-id:date:from:user-agent:mime-version:to:cc:subject :references:in-reply-to:content-type:content-transfer-encoding; b=MlN/aCDuYq8NZYou1bWs+Q0RQXwoDHvvIGkmk54BdLhTsYdXwgw8oyb4Nv1f5uqlOF qat8Y9//t6m9lF/OCi3hDOC0XcUjtvKgGEJgk3UmOdTTiZguYtdiblEBqluwAFpMCKI0 TEhcsc2GSg91B6tA4WKyyKNJPSU7xIUqDK/bQ= Received: by 10.213.1.142 with SMTP id 14mr892636ebf.40.1265368621716; Fri, 05 Feb 2010 03:17:01 -0800 (PST) Received: from ?0.0.0.0? (5357DA75.cable.casema.nl [83.87.218.117]) by mx.google.com with ESMTPS id 10sm4830292eyd.45.2010.02.05.03.17.00 (version=TLSv1/SSLv3 cipher=RC4-MD5); Fri, 05 Feb 2010 03:17:01 -0800 (PST) Message-ID: <4B6BFE33.5080809@gmail.com> Date: Fri, 05 Feb 2010 12:17:07 +0100 From: Yeb Havinga User-Agent: Thunderbird 2.0.0.23 (Windows/20090812) MIME-Version: 1.0 To: Glenn Maynard CC: pgsql-performance@postgresql.org Subject: Re: Slow query: table iteration (8.3) References: <603c8f071002031905w51dbea37y148284ea6546feda@mail.gmail.com> <2f4958ff1002040028j29e907c6l47e1f5efe83b667d@mail.gmail.com> In-Reply-To: Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Virus-Scanned: Maia Mailguard 1.0.1 X-Spam-Status: No, hits=-2.134 tagged_above=-10 required=5 tests=AWL=0.465, BAYES_00=-2.599 X-Spam-Level: X-Archive-Number: 201002/99 X-Sequence-Number: 37520 Glenn Maynard wrote: > The function version: > > CREATE FUNCTION high_score_for_user(user_id int) RETURNS SETOF INTEGER > LANGUAGE SQL AS $$ > SELECT t.id FROM test t > WHERE t.user_id = $1 > ORDER BY t.score DESC LIMIT 1 > $$; > SELECT high_score_for_user(u.id) FROM test_users u; > > runs in 100ms. > Hi Glenn, About cached plans of SQL functions: from the source of function.c 00067 /* 00068 * An SQLFunctionCache record is built during the first call, 00069 * and linked to from the fn_extra field of the FmgrInfo struct. 00070 * 00071 * Note that currently this has only the lifespan of the calling query. 00072 * Someday we might want to consider caching the parse/plan results longer 00073 * than that. 00074 */ So it is planned at every call of SELECT high_score_for_user(u.id) FROM test_users u; and the cache is used between each row of test_users. The plan is with a parameter, that means the optimizer could not make use of an actual value during planning. However, your test case is clever in the sense that there is an index on users and score and the sql function has an order by that matches the index, so the planner can avoid a sort by accessing the test table using the index. In this particular case, that means that the plan is optimal; no unneeded tuples are processed and the (function) plan complexity is logaritmic on the size of the test relation, you can't get it any better than that. In short: the lack of an actual parameter in the test case did not result in an inferior plan. So using a dynamic constructed query string in pl/pgsql to 'force' replanning during iteration cannot be faster than this sql function. It is possible to make the performance if this function worse by disabling indexscans: CREATE FUNCTION high_score_for_user(user_id int) RETURNS SETOF INTEGER LANGUAGE SQL AS $$ SELECT t.id FROM test t WHERE t.user_id = $1 ORDER BY t.score DESC LIMIT 1 $$ SET enable_indexscan = off; Now the query time with test_users is over a second. So maybe the converse could also be true in your production setup using the same technique. regards, Yeb Havinga