Thread: Statistical Analysis
I am having to perform a large data analysis query fairly frequently and the execution time is not exceptable, so I was looking at doing a statictical sample of the data to get fairly accurate results. Is there a way to perform a query on a set number of random rows instead of the whole dataset? I have looked through the documentation for a function that would do this, but I have not seen any. If this is a RTFM type question, then feel free to tell me so and point me in the right direction because I just haven't been able to find any info on it. Thanks ahead of time. --------------- Nathan Barnett
I don't think it's random (well, I'm sure it's not) but you could use LIMIT to get a smaller number of results... *shrug* just an idea. Good luck! -Mitch ----- Original Message ----- From: "Nathan Barnett" <nbarnett@cellularphones.com> To: <pgsql-general@postgresql.org> Sent: Monday, July 24, 2000 3:20 PM Subject: [GENERAL] Statistical Analysis > I am having to perform a large data analysis query fairly frequently and the > execution time is not exceptable, so I was looking at doing a statictical > sample of the data to get fairly accurate results. Is there a way to > perform a query on a set number of random rows instead of the whole dataset? > I have looked through the documentation for a function that would do this, > but I have not seen any. If this is a RTFM type question, then feel free to > tell me so and point me in the right direction because I just haven't been > able to find any info on it. > > Thanks ahead of time. > > > --------------- > Nathan Barnett > >
Are you grabbing a set of rows to work on in an outside app? You may be able to get a smaller random set with: select <whatever> from <table> order by random() limit <number> But this will pretty much force a sort step [and if you're not limiting the rows with a where clause, probably a full sequential scan] and could be very expensive depending on the number or matching rows for any limiting clauses you have. You'd have to play with it in practice to see if it's any faster. ----- Original Message ----- From: "Nathan Barnett" <nbarnett@cellularphones.com> To: <pgsql-general@postgresql.org> Sent: Monday, July 24, 2000 12:20 PM Subject: [GENERAL] Statistical Analysis > I am having to perform a large data analysis query fairly frequently and the > execution time is not exceptable, so I was looking at doing a statictical > sample of the data to get fairly accurate results. Is there a way to > perform a query on a set number of random rows instead of the whole dataset? > I have looked through the documentation for a function that would do this, > but I have not seen any. If this is a RTFM type question, then feel free to > tell me so and point me in the right direction because I just haven't been > able to find any info on it.
Stephan, The SORT is what I'm trying to avoid because I was using a group by to grab all the data in the groups that I needed, but it requires a sort to group by and this bottlenecked the query. I really just wanted to grab a sample of all the rows in the table and then perform the group by on the subset to avoid the overhead of sorting the whole table. My query has no where clauses and thus must sort through all of the data being analyzed. It then aggregates the data in a table that is then being used in the realtime queries. The analysis must be able to run every hour. ---------------- Nathan Barnett -----Original Message----- From: pgsql-general-owner@hub.org [mailto:pgsql-general-owner@hub.org]On Behalf Of Stephan Szabo Sent: Monday, July 10, 2000 3:49 PM To: Nathan Barnett; pgsql-general@postgresql.org Subject: Re: [GENERAL] Statistical Analysis Are you grabbing a set of rows to work on in an outside app? You may be able to get a smaller random set with: select <whatever> from <table> order by random() limit <number> But this will pretty much force a sort step [and if you're not limiting the rows with a where clause, probably a full sequential scan] and could be very expensive depending on the number or matching rows for any limiting clauses you have. You'd have to play with it in practice to see if it's any faster. ----- Original Message ----- From: "Nathan Barnett" <nbarnett@cellularphones.com> To: <pgsql-general@postgresql.org> Sent: Monday, July 24, 2000 12:20 PM Subject: [GENERAL] Statistical Analysis > I am having to perform a large data analysis query fairly frequently and the > execution time is not exceptable, so I was looking at doing a statictical > sample of the data to get fairly accurate results. Is there a way to > perform a query on a set number of random rows instead of the whole dataset? > I have looked through the documentation for a function that would do this, > but I have not seen any. If this is a RTFM type question, then feel free to > tell me so and point me in the right direction because I just haven't been > able to find any info on it.
Tim, Hmm... this might just work because I could actually perform myrandfunc() < .2 and then do a LIMIT on it for 10% or what not. That would almost gurantee the exact amount of rows. ----------------- Nathan Barnett -----Original Message----- From: keitt@ulysses.nceas.ucsb.edu [mailto:keitt@ulysses.nceas.ucsb.edu]On Behalf Of Timothy H. Keitt Sent: Monday, July 24, 2000 3:41 PM To: Nathan Barnett Subject: Re: [GENERAL] Statistical Analysis You would need to add a pseudorandom number function to postgresql. If your function returns numbers on [0, 1), then you could do: select * from mytable where myrandfunc() < 0.1; and get back (asymtotically) 10% of the rows. If you want exactly n randomly chosen rows, its a bit more expensive computationally. Another more involved approach would be to implement random cursors. This would be great for bootstrapping analysis. Tim Nathan Barnett wrote: > > I am having to perform a large data analysis query fairly frequently and the > execution time is not exceptable, so I was looking at doing a statictical > sample of the data to get fairly accurate results. Is there a way to > perform a query on a set number of random rows instead of the whole dataset? > I have looked through the documentation for a function that would do this, > but I have not seen any. If this is a RTFM type question, then feel free to > tell me so and point me in the right direction because I just haven't been > able to find any info on it. > > Thanks ahead of time. > > --------------- > Nathan Barnett -- Timothy H. Keitt National Center for Ecological Analysis and Synthesis 735 State Street, Suite 300, Santa Barbara, CA 93101 Phone: 805-892-2519, FAX: 805-892-2510 http://www.nceas.ucsb.edu/~keitt/
Nathan Barnett wrote: > > Stephan, > The SORT is what I'm trying to avoid because I was using a group by to grab > all the data in the groups that I needed, but it requires a sort to group by > and this bottlenecked the query. I really just wanted to grab a sample of > all the rows in the table and then perform the group by on the subset to > avoid the overhead of sorting the whole table. My query has no where > clauses and thus must sort through all of the data being analyzed. It then > aggregates the data in a table that is then being used in the realtime > queries. The analysis must be able to run every hour. What about using random() in the WHERE clause? Regards, Andrew. -- _____________________________________________________________________ Andrew McMillan, e-mail: Andrew@cat-it.co.nz Catalyst IT Ltd, PO Box 10-225, Level 22, 105 The Terrace, Wellington Me: +64 (21) 635 694, Fax: +64 (4) 499 5596, Office: +64 (4) 499 2267
Oops. Just tried that; the random() call only get evaluated once. What you need is a column type "random" that calls random() each time its evaluted. T. Andrew McMillan wrote: > > Nathan Barnett wrote: > > > > Stephan, > > The SORT is what I'm trying to avoid because I was using a group by to grab > > all the data in the groups that I needed, but it requires a sort to group by > > and this bottlenecked the query. I really just wanted to grab a sample of > > all the rows in the table and then perform the group by on the subset to > > avoid the overhead of sorting the whole table. My query has no where > > clauses and thus must sort through all of the data being analyzed. It then > > aggregates the data in a table that is then being used in the realtime > > queries. The analysis must be able to run every hour. > > What about using random() in the WHERE clause? > > Regards, > Andrew. > -- > _____________________________________________________________________ > Andrew McMillan, e-mail: Andrew@cat-it.co.nz > Catalyst IT Ltd, PO Box 10-225, Level 22, 105 The Terrace, Wellington > Me: +64 (21) 635 694, Fax: +64 (4) 499 5596, Office: +64 (4) 499 2267 -- Timothy H. Keitt National Center for Ecological Analysis and Synthesis 735 State Street, Suite 300, Santa Barbara, CA 93101 Phone: 805-892-2519, FAX: 805-892-2510 http://www.nceas.ucsb.edu/~keitt/
"Timothy H. Keitt" <keitt@nceas.ucsb.edu> writes: > Oops. Just tried that; the random() call only get evaluated once. Hmm, you're right. That's a bug. The system knows that random() can give different results on each call, but there's one piece of the planner that hasn't gotten the word :-( regards, tom lane
"Timothy H. Keitt" <keitt@nceas.ucsb.edu> writes: > Oops. Just tried that; the random() call only get evaluated once. Sigh, forgot to mention the solution. There's an undocumented function: * bool oidrand (oid o, int4 X)- * takes in an oid and a int4 X, and will return 'true' * about 1/X of the time. typically used like this: -- select roughly 1/10 of the tuples SELECT * FROM onek WHERE oidrand(onek.oid, 10); This doesn't get collapsed by the overly aggressive constant-qual recognizer because it takes a table column as input. (The function doesn't actually *use* the OID, mind you, but the planner doesn't know that. What a kluge... but it gets the job done.) Note that this isn't necessarily going to fix your performance problem, since a scan of the whole input table is still going to be required. But if the expensive processing was somewhere downstream of that basic scan, it should help. regards, tom lane
Tom Lane wrote: > > Note that this isn't necessarily going to fix your performance problem, > since a scan of the whole input table is still going to be required. > But if the expensive processing was somewhere downstream of that basic > scan, it should help. > The only way that I know of to do this fast is to insert the items in random order. I've done this (in C++, not postgres) using a map (b-tree) data structure: insert key-value pairs with the key being a random number; then pop entries off the tail of the map as needed. Tim -- Timothy H. Keitt National Center for Ecological Analysis and Synthesis 735 State Street, Suite 300, Santa Barbara, CA 93101 Phone: 805-892-2519, FAX: 805-892-2510 http://www.nceas.ucsb.edu/~keitt/
At 20:18 24/07/00 -0400, you wrote: >Sigh, forgot to mention the solution. There's an undocumented function: > > * bool oidrand (oid o, int4 X)- > * takes in an oid and a int4 X, and will return 'true' > * about 1/X of the time. > >typically used like this: > >-- select roughly 1/10 of the tuples >SELECT * FROM onek WHERE oidrand(onek.oid, 10); > It doesnt seem to work as you explain. For a value of 1 you expect (nearly) all the tuples and two should return half, but that not what I'm finding. galore=> select count(*) from topten where room='HI'; count ----- 14 (1 row) galore=> SELECT * FROM topten WHERE room='HE' and oidrand(topten.oid, 1); type|data |norder|room |grp ----+-------------------------+------+------+--- B |0764552503 | 1|HE | B |0751327190 | 1|HE | B |0718144392 | |HE | B |0500280754 | |HE | B |0028610091 | 1|HE | (5 rows) galore=> SELECT * FROM topten WHERE room='HE' and oidrand(topten.oid, 2); type|data |norder|room |grp ----+-------------------------+------+------+--- B |0764552503 | 1|HE | B |0751327190 | 1|HE | B |0718144392 | |HE | (3 rows) galore=> SELECT * FROM topten WHERE room='HE' and oidrand(topten.oid, 7); type|data |norder|room |grp ----+-------------------------+------+------+--- B |0751327190 | 1|HE | B |0718144392 | |HE | (2 rows) -- thorNET - Internet Consultancy, Services & Training Phone: 01454 854413 Fax: 01454 854412 http://www.thornet.co.uk
Steve Heaven wrote: > > At 20:18 24/07/00 -0400, you wrote: > >Sigh, forgot to mention the solution. There's an undocumented function: > > > > * bool oidrand (oid o, int4 X)- > > * takes in an oid and a int4 X, and will return 'true' > > * about 1/X of the time. > > > >typically used like this: > > > >-- select roughly 1/10 of the tuples > >SELECT * FROM onek WHERE oidrand(onek.oid, 10); > > > > It doesnt seem to work as you explain. > For a value of 1 you expect (nearly) all the tuples and two should return > half, but that not what I'm finding. > > galore=> select count(*) from topten where room='HI'; > count > ----- > 14 > (1 row) > > galore=> SELECT * FROM topten WHERE room='HE' and oidrand(topten.oid, 1); > type|data |norder|room |grp > ----+-------------------------+------+------+--- > B |0764552503 | 1|HE | > B |0751327190 | 1|HE | > B |0718144392 | |HE | > B |0500280754 | |HE | > B |0028610091 | 1|HE | > (5 rows) > galore=> SELECT * FROM topten WHERE room='HE' and oidrand(topten.oid, 2); > type|data |norder|room |grp > ----+-------------------------+------+------+--- > B |0764552503 | 1|HE | > B |0751327190 | 1|HE | > B |0718144392 | |HE | > (3 rows) > galore=> SELECT * FROM topten WHERE room='HE' and oidrand(topten.oid, 7); > type|data |norder|room |grp > ----+-------------------------+------+------+--- > B |0751327190 | 1|HE | > B |0718144392 | |HE | > (2 rows) > -- > thorNET - Internet Consultancy, Services & Training > Phone: 01454 854413 > Fax: 01454 854412 > http://www.thornet.co.uk Isn't it because oidrand evals as 'random() < 1/X' ? or maybe 'random() < 1/(X+1)' ? -- Guillaume Perréal - Stagiaire MIAG Cemagref (URH), Lyon, France Tél: (+33) 4.72.20.87.64