X-Original-To: pgsql-sql-postgresql.org@localhost.postgresql.org Received: from localhost (unknown [200.46.204.144]) by svr1.postgresql.org (Postfix) with ESMTP id B581FD1B8A9 for ; Thu, 17 Jun 2004 00:04:45 -0300 (ADT) Received: from svr1.postgresql.org ([200.46.204.71]) by localhost (av.hub.org [200.46.204.144]) (amavisd-new, port 10024) with ESMTP id 02981-09 for ; Thu, 17 Jun 2004 03:03:56 +0000 (GMT) Received: from biglumber.com (biglumber.com [207.228.252.42]) by svr1.postgresql.org (Postfix) with SMTP id 0D756D1C975 for ; Thu, 17 Jun 2004 00:03:31 -0300 (ADT) Received: (qmail 31013 invoked from network); 17 Jun 2004 03:03:31 -0000 Received: from unknown (HELO localhost) (207.228.252.42) by 0 with SMTP; 17 Jun 2004 03:03:31 -0000 From: "Greg Sabino Mullane" To: pgsql-sql@postgresql.org Subject: Re: Is there a faster way to do this? X-PGP-Key: 2529 DF6A B8F7 9407 E944 45B4 BC9B 9067 1496 4AC8 X-Request-PGP: http://www.biglumber.com/x/web?pk=2529DF6AB8F79407E94445B4BC9B906714964AC8 In-Reply-To: Date: Thu, 17 Jun 2004 03:03:31 -0000 X-Mailer: JoyMail 1.48 Message-ID: X-Virus-Scanned: by amavisd-new at hub.org X-Spam-Status: No, hits=0.0 tagged_above=0.0 required=5.0 tests= X-Spam-Level: X-Archive-Number: 200406/144 X-Sequence-Number: 18089 -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Hard to imagine it taking that long, even for a table that large, but we don't know the details of your system. I got a sample table with 800,000 records down to 92 seconds using the function below. See how it does for you. Notes follow. CREATE OR REPLACE FUNCTION percentile_calc(INTEGER) RETURNS text AS ' DECLARE v_tile ALIAS FOR $1; v_interval integer; v_record record; v_rowcount integer := 0; v_percentile integer := 1; BEGIN SELECT COUNT(*)/v_tile FROM cdm_indiv_mast WHERE val_purch_com > 0 INTO v_interval; FOR v_record IN SELECT ctid FROM cdm_indiv_mast WHERE val_purch_com>0 ORDER BY val_purch_com DESC LOOP v_rowcount := v_rowcount + 1; UPDATE cdm_indiv_mast SET percentiler=v_percentile WHERE ctid = v_record.ctid; IF v_rowcount >= v_interval THEN v_percentile := v_percentile + 1; v_rowcount := 0; END IF; END LOOP; RETURN \'DONE\'; END; ' LANGUAGE plpgsql STABLE STRICT; CREATE OR REPLACE FUNCTION percentile_calc() RETURNS text AS 'SELECT new10(100);' LANGUAGE SQL; Notes: Since 100 seemed to be hard-coded into the original function, there was no need for v_count. Instead, I made "v_tile" a variable, with a default of "100" if the function is called with no argument. There may be a false assumption here. If the values of val_purch_com are not unique, then two items with the same val_purch_com may have different percentiler values. If this is the case, you may want to at least enforce some ordering of these values by adding more to the ORDER BY clause. Without knowing the full table structure, I can't recommend what columns to add there. To really speed this up, make sure that you do not have any indexes on the table. By using tids, we neatly avoid having to use any indexes in the function itself. Unless you are using oids and really need them (highly unlikely because of the "indiv_key" column), you should remove them: ALTER TABLE cdm_indiv_mast SET WITHOUT OIDS; Of course, vacuuming completely and often is recommended for a table this size as well, especially when updating this many rows at once. I'd recommend a VACUUM FULL immediately before running it. - -- Greg Sabino Mullane greg@turnstep.com PGP Key: 0x14964AC8 200406162303 -----BEGIN PGP SIGNATURE----- iD8DBQFA0QpdvJuQZxSWSsgRAk88AKDtGrs6+/ypaaNU6DWqvhCgtsrM0gCg+2ve J8JKOPgxp42c54Nx/rzHdxs= =sNFW -----END PGP SIGNATURE-----