From: Subject: Getting a Random Sample of Records Date: Mon, 16 Oct 2006 13:20:20 +0800 MIME-Version: 1.0 Content-Type: multipart/related; boundary="----=_NextPart_000_0000_01C6F125.D48E0900"; type="text/html" X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1506 This is a multi-part message in MIME format. ------=_NextPart_000_0000_01C6F125.D48E0900 Content-Type: text/html; charset="Windows-1252" Content-Transfer-Encoding: quoted-printable Content-Location: http://www.revealnet.com/newsletter-v2/randomising.htm Getting a Random Sample of Records


Reprinted with = Permission by=20 RevealNet, Inc.  March=20 2001

Getting a random sample of records
the good the bad = and the=20 ugly=85.

One common requirement = that crops up=20 from time to time is that someone will want a random sample of records = from your=20 database. A common example of this is where a marketing department makes = what at=20 first may seem like a simple request. "Could we have a list of 1000 = potential=20 customer addresses matching criteria x and y and z. Oh, = and if=20 there are more than 1000 people matching the criteria then can we choose = those=20 people randomly from the total set of people."

At first sight you may = thing that this=20 is easily done by not ordering the output from whatever query you use = and then=20 reading as many records as you require from the output. This is often a = mistake=20 made by the novice as Oracle tends to return the rows in the same order = each=20 time if you don=92t give an order-by clause. The next thing you may do = is to reach=20 for the manual to look at the dbms_random package without really = thinking=20 through what it is that you want to do. Its certainly what I = did.

The two solutions that I = considered and=20 rapidly dismissed were as follows:

The bad = solution

This was the easiest to = code but was=20 immensely inefficient. It went like this "If you need 100 records, get = 100=20 random numbers using dbms_random package and read until the rownum = equals the=20 random number". I dismissed this idea in less time than it took to = describe it=20 as this is obviously just too inefficient. The inefficiency lay in the = fact that=20 if your random number generator selected rows 500, 10000 and 2000 you = need to=20 read 12500 records to get at those 3 random records. As the number of = random=20 records you require gets bigger, the overhead associated with this = method=20 becomes massive.

The ugly = solution.

This grew from the = previous idea. I=20 wanted to cut down the number of records required to be read in order to = get at=20 those random records. So where is the overhead =96 in the repeated = reading of all=20 those records =96 if you read 1 to 10000 to get the 10000th = record you=20 don=92t want to read 1 to 500 to get the 500th record as you = have=20 already read them once. The solution I came up with was to load all of = the=20 records into a plsql table and then use the dbms_random package again to = give me=20 random numbers. These I then could use as the index to the record in the = plsql=20 table. The benefits of this solution are that it is relatively quick and = it=20 reduces the number of records read. The number of records read is = (number of=20 rows in table) + (number of records read from plsql table). As the main=20 component is reading all the records to the plsql table, the response = time for=20 the query should change very little. Now this solution works but it is = not very=20 pretty =96 the reason being that what you have is a procedure which = writes output=20 to a file perhaps or to a temporary table. This is probably acceptable = but not=20 necessarily the nicest way we can do this. It would be nicer if the = solution was=20 simpler and could be incorporated into simple sql.

The good = solution.

The solution I finally = landed on came=20 out of a conversation with one of my workmates. Basically he pointed me = in the=20 direction of a function in dbms_utility called GET_HASH_VALUE. I think = this was=20 new in 8.15 although it may predate this release. At its simplest, all = this=20 function does is accept a string and return a number associated with it. = The=20 nice thing about this is that if you select this function as part of a = sql=20 statement you can then order your returned rows by something that bears = no=20 relationship to the order of the data. Using the solution I am about to = explain,=20 you end up with a view where the records are returned in a different = order every=20 time you query it!

The = DBMS_UTILITY.GET_HASH_VALUE=20 function

The specification for the = function is=20 as follows

DBMS_UTILITY.GET_HASH_VALUE

(

name = VARCHAR2,

base = NUMBER,

hash_size=20 NUMBER

)RETURN=20 NUMBER;

 

PRAGMA=20 restrict_references(GET_HASH_VALUE, WNDS, RNDS, WNPS,=20 RNPS);

The really nice thing = about the=20 function, the thing that makes it useful for us is that PRAGMA. The = bottom line=20 is that we can now use it as part of a sql statement or as part of a=20 view.

Parameters

There are three IN parameters to the=20 function

Name = :- Text string to be used as the basis of the = hashing.

Base = :- The lowest number you want for the hash = value.

Hash_size:- Size of the hash=20 table.

Returns

A numeric value which is = derived from=20 the IN parameter =91name=92.

How we use the function to get random=20 records.

What I want to do here is = create a view=20 onto the table(s) that I want to look at. In the following example you = can see=20 that I have used the =91emp=92 table =96 lets say we want to find 5 = random employees=20 in our organisation to ask about how they feel about working = conditions....=20 Basically I will create a view onto the emp table, including a call to = the=20 get_hash_value function and making the view order on that=20 pseudocolumn.

CREATE OR = REPLACE VIEW=20 random_employees AS

SELECT=20 DBMS_UTILITY.GET_HASH_VALUE

(

TO_CHAR(dbms_utility.get_time)||ename

,2

,1048576

)=20 "RANDOM_ORDER"

, = emp.*

FROM = EMP

ORDER BY=20 RANDOM_ORDER

In this example I chose = 1048576 for the=20 size of the hash table as oracle recommends that the size be a power of = 2. Given=20 that the lowest value is only 2, the highest will be 1048578 (2 + = 1048576). You=20 may not have seen dbms_utility.get_time function before =96 this is a = nice (and=20 also pragma=92d) function that returns elapsed time in 100th = of a=20 second.

When you have created the = view, select=20 from it where the rownum is less than your desired maximum number or = required=20 records. Because the hash value for each row is dependant upon the time = in=20 hundredths of a second concatenated to the surname, the hash value for = each row=20 will be different each time you select from the view.

In this way the order or = the records=20 changes with time and hence if you select only the first 4 records you = will get=20 different records each time.

SQL> select ename from random_employees = where rownum=20 < 5;

 

ENAME

----------

WARD

KING

ALLEN

JAMES

 

SQL> select ename from random_employees = where rownum=20 < 5;

 

ENAME

----------

JONES

TURNER

WARD

CLARK

 

SQL> select ename from random_employees = where rownum=20 < 5;

 

ENAME

----------

JONES

JAMES

CLARK

ADAMS

As there are only 14 rows = in the table=20 in total, some employees will turn up in each select as we are picking = 28% of=20 the rows in this particular table at random.

Hopefully from this you = can see how=20 easy it is to get a random set of records from a query. While the = example is=20 pretty superficial, the same technique could be applied to your list of=20 customers for mailing, a list of financial accounts for random checking, = getting=20 a random list of batch numbers for random quality control=20 checks.

------=_NextPart_000_0000_01C6F125.D48E0900 Content-Type: image/gif Content-Transfer-Encoding: base64 Content-Location: http://www.revealnet.com/newsletter/design1.gif R0lGODlhPwA/APcAAAAxMQBCQgBSUgBjYwBzcwB7ewCEhACMhAhSUghzcwiclBA5ORBCQhBraxCM jBCUlCFaWiF7eymtrSm9vTE5MTFKSjFrazF7ezGcnDGtrTG9vUJjY0Jzc0KMjEK9vULGxkpCQkpS SkqlpVJjY1paWlp7e2NjY2OEhGtra2ulpWu1tXNzc3OUlHsQEHtCQnt7e3uMjHutrXu9vYR7e4SU lISlpYxjY4yMjIy1tZSlpZTGxpwxMZyMjJycnKVCQqWMjKWUlKWlpa0pKa0xMa2trbUQELUpKbWt rbW9vbXe3rXn5717e729vb3Gxr3OzsaMjM4AAM57e869vc7OztbW1t7e3t7v7+cpKefn5+8AAO/3 9/fv7/f39/f///8AAP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAA/AD8A AAj+AL8IxDKFSUEmCBMqXMgQoZSGECMyIYKwisAvWwxWobLlYMGPBkOCHGlQh8iTJElKcfKQIpEe UwRWxNhxykOVKJnclCIlRoYONlfe1MkypNCcRI68hFmFCMUqBykiQXiESdWpVK0mJCIlhQINAjpk 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 AhP0IJ8X6cheFGKWuTSaIVchy1j4GBAAOw== ------=_NextPart_000_0000_01C6F125.D48E0900 Content-Type: image/gif Content-Transfer-Encoding: base64 Content-Location: http://www.revealnet.com/newsletter/title_sm.gif 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 ------=_NextPart_000_0000_01C6F125.D48E0900--