orawin.info

Niall's Oracle Pages – Oracle Opinion since 2004

In Praise of Clones

with 5 comments

I’m all alone, so are we all
We’re all clones
All are one and one are all

~ Alice Cooper

Two separate discussions, one at work and one around the virtual OakTable , have made me aware that maybe not as many Oracle professionals as I imagined are aware that Oracle provides a facility to clone Oracle Software homes, either to a new home on the same machine, or to a new home on a brand new machine with the same build. This process is far quicker than the graphical installation routine, or even than a straightforward silent install using OUI. It also lends itself very neatly to quickly provisioning identical builds of database servers. I thought therefore I’d jot down my notes on how I recently did just that for a data guard demo environment.

Servers Involved

I had 2 servers involved here, their setup is as follows:

Purpose Server Physical IP Address SID
Primary Server DB11-2-NODE1 192.168.56.11/24 db11gr2
Standby Server DB11-2-NODE2 192.168.56.11/24 db11g_stdby

The servers are both running my favourite RHEL clone CentOS, in this case the Release 5.6.

Initial Setup

After installing the O/S, updating the kernel for security patches I installed the following products in /u01/app/oracle/product/11.2.0/dbhome_1 on node1.

  • Oracle Database 11.2.0.2
  • Oracle July PSU (12419331 )

The above process took approximately 2 hours including media download and basic server documentation.

Gold Image

At this point I could have simply repeated the process on node 2. However cloning is much easier and repeatable.  First I made a Gold Image by running the following as root on node 1. /media/dsl/database/linux/11.2 is a mount point containing my gold images.

cd /u01/app/oracle/product/11.2.0/dbhome_1
tar -cpvzf /media/dsl/database/linux/11.2/db112023.tgz .

Cloning

On the second machine I also mounted my DSL as above and then ran the following script

./installOracle.sh /media/dsl/database/linux/11.2/db112023.tgz /u01/app/oracle/product/11.1.0/dbhome_1 /u01/app/oracle OracleHome1

where installOracle.sh reads as follows

#!/usr/bin/ksh
#
# Install gold image of Oracle using clone home functionality of OUI.
#
# Expects parameters <name of image> <install_loc> <Oracle Home Name>
# Assumes Pre-Reqs are met -- TODO add pre-req fixing
# assumes unzip installed
#
if [[ $# -ne 4 ]]; then
 echo "Usage : installOracle.sh imageName instLoc oracle_base HomeName";
 echo " : eg installOracle.sh /media/dbhome111.tgz /u01/app/oracle/product/11.1.0/db_1 /u01/app/oracle OracleHome11g"
 exit 1;
fi

IMAGE=$1
INSTLOC=$2
ORABASE=$3
HOMENAME=$4

echo "Making Oracle Home Directory"
mkdir -p ${INSTLOC}
chown -R oracle:oinstall ${ORABASE}
cd ${INSTLOC}
echo "Extracting Archive at $(date +%Y%M%d%m)"
tar -xvzf ${IMAGE}
cd clone/bin
echo "Cloning Home........."
sudo -u oracle perl clone.pl ORACLE_HOME="${INSTLOC}" ORACLE_HOME_NAME="${HOMENAME}" ORACLE_BASE="${ORABASE}" -ignoreSysPrereqs
${INSTLOC}/root.sh
echo "Install Finished at $(date +%Y%M%d%m)"
echo "Please run any non root.sh scripts as instructed above. root.sh has been run"

This code has to be run as root. It does the following

  • creates the home directory
  • extracts the gold image from the tarball
  • runs a perl script as the oracle user
  • runs root.sh

This script completed in less than 10 minutes on an identical virtual machine to the one that had taken 2 hours to perform the complete install and patching process.

Metalink Reference : How to clone an Oracle Database Home using OUI 

Possibly Related Posts:

  • No Related Posts found

Written by Niall Litchfield

July 27th, 2011 at 3:20 pm

Posted in Uncategorized

Tagged with , ,

Another World XI

with one comment

In celebration of Test Match 2000 (where surely Sachin Tendulkar is due to complete his century of centuries – albeit in a losing cause :) ) The ICC have a new poll looking for an all time XI. You have til midnight tonight to complete it Mine is the same as the World XI I put together, with the inclusion of Sobers as a mandatory all rounder.

Possibly Related Posts:

Written by Niall Litchfield

July 13th, 2011 at 10:49 am

Posted in Uncategorized

Tagged with

Operating System Interaction

without comments

The excellent Madrid from the otn forums has a nice post here on a particular listener error caused by not following the install instructions precisely. I thought that I’d dig in a little further to illustrate the interplay between the O/S and our wonderful C program that is oracle.exe

The message Hector got was

Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=echo.world)(PORT=15
21)))
TNS-12535: TNS:operation timed out
TNS-12560: TNS:protocol adapter error
TNS-00505: Operation timed out
32-bit Windows Error: 60: Unknown error

 

what has happened here is that our program (oracle.exe) has made an o/s call and got an o/s error message that it doesn’t know about. That doesn’t mean that the code is undocumented though. You can find the Windows system error codes at this useful page on MSDN. Here you will find that error 60 means

ERROR_BAD_REM_ADAP – The adaptor is not capable.

Which is a pretty clear indication that there is a network adapter issue. What is slightly more surprising is the error message shown in the trace file. The relevant output is


2011-07-05 15:09:59.249389 : nsc2addr:(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=echo.oracle.com)(PORT=1521)))
2011-07-05 15:09:59.249561 : snlinGetAddrInfo:getaddrinfo() failed with error 11001

The initial line is the Oracle Net  function to extract a host address from the net service name the second line is the actual failure, However the return code 11001 corresponds to a windows socket error in name resolution

The main point to make here is that where Oracle calls os functions and gets unexpected results, then it maybe time to dig into the os calls. MSDN is a great resource for this as is the Windows Internals book.

 

 

Possibly Related Posts:

Written by Niall Litchfield

July 7th, 2011 at 2:57 pm

Posted in Uncategorized

Tagged with , ,

php long numbers

with one comment

I got a mail from long time Oracle guy Joel Garry regarding the twitter widget in the right hand column.

On orawin.info, you have a twitter feed, where each entry has a date/time link on it.  But those links look like http://twitter.com/nlitchfield/statuses/8.0773403426E+16 which look to me like something is translating a big number to scientific notation…?

Well Joel was right. Something was translating a large number to scientific notation. That something turns out to be php itself. Twitter status updates are (apparently) a simple ever increasing integer. There are now a lot of twitter status updates. As this page shows recent versions of php will automatically display that in scientific notation unless explicitly told otherwise. Now I personally think that this is an odd thing for php to choose to do, but us database folks surely recognize the folly of the plugin programmers relying on default formats. Anyway my version of the plugin is now fixed – based on this forum post - and thanks to Joel for the heads up. Anyone reading this who programs in php against databases that might return large numbers might wish to reveiw their web pages for appropriate results.

Possibly Related Posts:

Written by Niall Litchfield

June 17th, 2011 at 7:48 am

Posted in Uncategorized

Tagged with ,

Index Rebuilds – A new Myth arrives

without comments

Just over 9 years ago now, before usenet died , I posted a list of common myths regarding the Oracle RDBMS. You can find that list and the ensuing discussion here. Number 2 in my list was

Free Space in an index is never reused.

At the time it was commonly thought that indexes needed regular rebuilding to avoid fragmentation. The best work I am aware of that describes why this is not the case is Richard Foote’s Index Internals: Rebuilding the Truth paper. Over time more and more people have come to quote this work and it is often cited in discussions on the forums at OTN and elsewhere.  Recently I have noticed a tendency for people to produce answers like the one in this answer. Namely

In Enterprise Manager, the section named “Segment Advisor” can to help you <decide what indexes need rebuilding>

This it seems to me is a fundamental misunderstanding of what the segment advisor is showing you, and sadly is my second myth rising anew from the dead. The official documentation on the segment advisor describes it as

Over time, updates and deletes on objects within a tablespace can create pockets of empty space that individually are not large enough to be reused for new data. This type of empty space is referred to as fragmented free space.

Objects with fragmented free space can result in much wasted space, and can impact database performance. The preferred way to defragment and reclaim this space is to perform an online segment shrink. This process consolidates fragmented free space below the high water mark and compacts the segment. After compaction, the high water mark is moved, resulting in new free space above the high water mark. That space above the high water mark is then deallocated. The segment remains available for queries and DML during most of the operation, and no extra disk space need be allocated.

You use the Segment Advisor to identify segments that would benefit from online segment shrink. Only segments in locally managed tablespaces with automatic segment space management (ASSM) are eligible. Other restrictions on segment type exist. For more information, see “Shrinking Database Segments Online”.

If a table with reclaimable space is not eligible for online segment shrink, or if you want to make changes to logical or physical attributes of the table while reclaiming space, then you can use online table redefinition as an alternative to segment shrink. Online redefinition is also referred to as reorganization. Unlike online segment shrink, it requires extra disk space to be allocated. See “Redefining Tables Online” for more information.

In other words the segment advisor is all about reclaiming space. But a B*-Tree index will always tend to have free space within it – and will nearly always be able to reuse that space. Fragmentation as described above, that is unusable free space, does not apply to B*-Tree indexes in general in Oracle (the point of my previous post was to show one situation where it can be an issue) . To run the segment advisor on an index then is fundamentally misguided. As the next section describes the advisor is really intended for objects that actually store data (most commonly heap tables).

The Segment Advisor generates the following types of advice:

  • If the Segment Advisor determines that an object has a significant amount of free space, it recommends online segment shrink. If the object is a table that is not eligible for shrinking, as in the case of a table in a tablespace without automatic segment space management, the Segment Advisor recommends online table redefinition.
  • If the Segment Advisor determines that a table could benefit from compression with the OLTP compression method, it makes a recommendation to that effect. (Automatic Segment Advisor only. See “Automatic Segment Advisor”.)
  • If the Segment Advisor encounters a table with row chaining above a certain threshold, it records that fact that the table has an excess of chained rows.

Please don’t lets reinvent the old myths – there’s plenty of room for new ones out there.

Possibly Related Posts:

Written by Niall Litchfield

June 2nd, 2011 at 3:20 pm

Posted in Uncategorized

Tagged with , ,

Monotonically Increasing Indexes

with 5 comments

Richard Foote has put up another excellent rebuttal of the myth that you should rebuild indexes based on the value of del_lf_rows/lf_rows from an appropriately valideated index structure. Greg asked a question similar to my comment on the OTN forums in this thread. Namely

Is Oracle able to reuse index space when indexed column is like current date (monolitically increasing). So if we delete some old rows (past dates) and inserted new rows are with higer (more recent) dates . Does Oracle reuse space from deleted rows ?

The short answer to Greg is that the Radiohead example Richard uses shows that index space is reused for montonically increasing indexes where the old data is completely deleted. What happens is that the block gets put back on the freelist and is eligible for reuse as a new leaf block. This pattern of insert, process, delete old is pretty common. Sometimes however not *all* the old data gets deleted. In this case Oracle won’t re-use the free space. I have modified Richard’s example so that I delete all the non-prime values below a threshold. Due to the pattern of distribution of the primes this should leave a relatively large number of almost empty index blocks. In this case we see that the old space is not reused until the laggard’s have been finally deleted. NB if you are tempted to use my prime number test, feel free but be aware it degrades as the value of n grows. In other words I only warrant accuracy for positive numbers, not performance. In my case a significant percentage of the available space is left held by these ‘old’ entries. It’s worth remembering however that

  1. the ratio can’t tell you if you have a pattern that matches this usage and
  2. in most cases you’d want to investigate why these values weren’t being deleted anyway.
NIALL @ NIALL1 >@index_deletes
NIALL @ NIALL1 >drop table rush purge;

Table dropped.

Elapsed: 00:00:03.83
NIALL @ NIALL1 >
NIALL @ NIALL1 >create table rush(
  2  	     id number
  3  ,	     code number
  4  ,	     name  varchar2(30)
  5  );

Table created.

Elapsed: 00:00:00.02
NIALL @ NIALL1 >
NIALL @ NIALL1 >insert into rush
  2  select rownum,mod(rownum,100),'MOVING PICTURES'
  3  FROM dual
  4  connect by level <= 1000000; 

1000000 rows created.
Elapsed: 00:00:03.18 

NIALL @ NIALL1 >commit;

Commit complete.

Elapsed: 00:00:00.03
NIALL @ NIALL1 >
NIALL @ NIALL1 >create unique index pk_rush on rush(id);

Index created.

Elapsed: 00:00:05.64
NIALL @ NIALL1 >
NIALL @ NIALL1 >alter table rush
  2  add constraint pk_rush
  3  primary key (id) using index;

Table altered.

Elapsed: 00:00:00.14
NIALL @ NIALL1 >
NIALL @ NIALL1 >
NIALL @ NIALL1 >create or replace function is_prime(p in number) return number
  2  is
  3  	     l_limit number;
  4  	     i	     number := 3;
  5  	     retval  number := 1;  -- returns 0 if false, 1 if true
  6  begin
  7  	     l_limit := sqrt(p);
  8  	     if p = 1 then
  9  		     retval:=1;
 10  	     end if;
 11  	     if p = 2 then
 12  		     retval :=1;
 13  	     end if;
 14
 15  	     if mod(p,2) = 0 then
 16  		     retval := 0;
 17  	     end if;
 18
 19  	     while (i <= l_limit) loop
 20  		if mod(p,i) = 0 then
 21  			     retval := 0;
 22  		end if;
 23  		i := i + 2; -- (no need to test even numbers)
 24  	     end loop;
 25  	     return retval;
 26  end;
 27  /
Function created.
Elapsed: 00:00:00.00
NIALL @ NIALL1 >
NIALL @ NIALL1 >show errors
No errors.
NIALL @ NIALL1 >
NIALL @ NIALL1 >delete from rush
  2  where id < 400000
  3  and is_prime(id) = 0;

 366139 rows deleted.
Elapsed: 00:01:15.54
NIALL @ NIALL1 >
NIALL @ NIALL1 >commit;

Commit complete.

Elapsed: 00:00:00.01
NIALL @ NIALL1 >
NIALL @ NIALL1 >analyze index pk_rush validate structure;

Index analyzed.

Elapsed: 00:00:00.97
NIALL @ NIALL1 >
NIALL @ NIALL1 >select lf_rows,del_lf_rows,round(del_lf_rows/lf_rows,2) del_pct
  2  from index_stats;

   LF_ROWS DEL_LF_ROWS    DEL_PCT
---------- ----------- ----------
   1000000      366139        .37

1 row selected.

Elapsed: 00:00:00.03
NIALL @ NIALL1 >
NIALL @ NIALL1 >begin
  2  for i in 1000001..1400000 loop
  3  insert into rush
  4  values(i,mod(i,100),'GRACE UNDER PRESSURE');
  5  end loop;
  6  commit;
  7  end;
  8  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:47.54
NIALL @ NIALL1 >
NIALL @ NIALL1 >analyze index pk_rush validate structure;

Index analyzed.

Elapsed: 00:00:00.49
NIALL @ NIALL1 >
NIALL @ NIALL1 >select lf_rows,del_lf_rows,round(del_lf_rows/lf_rows,2) del_pct
  2  from index_stats;

   LF_ROWS DEL_LF_ROWS    DEL_PCT
---------- ----------- ----------
   1400000      366139        .26

1 row selected.

Elapsed: 00:00:00.02
NIALL @ NIALL1 >
NIALL @ NIALL1 >
NIALL @ NIALL1 >
NIALL @ NIALL1 >
NIALL @ NIALL1 >begin
  2  for i in 1400001..2000000 loop
  3  insert into rush
  4  values(i,mod(i,100),'2112');
  5  end loop;
  6  commit;
  7  end;
  8  /

PL/SQL procedure successfully completed.

Elapsed: 00:01:08.89
NIALL @ NIALL1 >
NIALL @ NIALL1 >analyze index pk_rush validate structure;

Index analyzed.

Elapsed: 00:00:00.63
NIALL @ NIALL1 >
NIALL @ NIALL1 >select lf_rows,del_lf_rows,round(del_lf_rows/lf_rows,2) del_pct
  2  from index_stats;

   LF_ROWS DEL_LF_ROWS    DEL_PCT
---------- ----------- ----------
   2000000      366139        .18

1 row selected.

Elapsed: 00:00:00.02
NIALL @ NIALL1 >spoo off

Possibly Related Posts:

Written by Niall Litchfield

May 23rd, 2011 at 10:02 am

Posted in Uncategorized

Tagged with , ,

When is a Health Check not a Health Check

with 3 comments

Thanks to The Human Fly via Twitter @sjaffarhussain I see that Oracle Corporation have a published note on How to Perform a Database Health Check. (Note 122669.1). I read this with some interest as this is something that I do quite frequently as part of my day job. (If you’d like to get me to take a look at one of your databases drop us a line). Here is the contents list of that note.
1. Parameter file
2. Controlfiles
3. Redolog files
4. Archiving
5. Datafiles
5.1 Autoextend
5.2 Location
6. Tablespaces
6.1 SYSTEM Tablespace
6.2 SYSAUX Tablespace (10g Release and above)
6.3 Locally vs Dictionary Managed Tablespaces
6.4 Temporary Tablespace
6.5 Tablespace Fragmentation
7. Objects
7.1 Number of Extents
7.2 Next extent
7.3 Indexes
8. AUTO vs MANUAL undo
8.1 AUTO UNDO
8.2 MANUAL UNDO
9. Memory Management
9.1 Pre Oracle 9i
9.2 Oracle 9i
9.3 Oracle 10g
9.4 Oracle 11g
10. Logging & Tracing
10.1 Alert File
10.2 Max_dump_file_size
10.3 User and core dump size parameters
10.4 Audit files
The paper introduces each of these areas – so for example the section on control files reads (in it’s entirety)
It is highly recommended to have at least two copies of the controlfile. This can be done by mirroring the controlfile, strongly recommended on different physical disks. If a controlfile is lost, due to a disk crash for example, then you can use the mirrored file to startup the database. In this way fast and easy recovery from controlfile loss is obtained.
connect as sysdba
SQL> select status, name from v$controlfile;

STATUS NAME

------- ---------------------------------

/u01/oradata/L102/control01.ctl

/u02/oradata/L102/control02.ctl

The location and the number of controlfiles can be controlled by the
‘control_files’ initialization parameter.

I’m rather a pedant so would rather the document be described as a “Best Practices” or “Guidelines “document than a how to. A How to document would reword the above as

Ensure that the database has at least 2 controlfiles located on different disks by reviewing the ‘control_files’ initialisation parameter.

I.E it told you How to do something, hence the name. But my beef isn’t really that this is yet another Best Practices document, but rather with what it leaves out. This is perhaps best illustrated by referring you to this forum thread. A health check that doesn’t ensure recoverability is no health check.

Possibly Related Posts:

Written by Niall Litchfield

May 16th, 2011 at 8:34 am

Posted in Uncategorized

Tagged with

blogs.oracle.com.

with one comment

As some of you will have noticed blogs.oracle.com has recently moved platform from Movable Type to Roller. This appears to be essentially the old blogs.sun.com platform. I do have some issues with it though – most notably the fact that the blog search now requires an oracle.com SSO account and doesn’t return results that it ought to. I’ve therefore knocked up a quick custom search engine for blogs.oracle.com that you can find at http://orawin.info/blog/search-oracle-blogs or on the local pages link on the right. Unlike Oracle I don’t intend this link to move – and if it does for some as yet unknown reason I’ll put a redirect in place.

Possibly Related Posts:

Written by Niall Litchfield

May 9th, 2011 at 9:33 am

Posted in Uncategorized

Tagged with

Random Thoughts

with one comment

I’ve been considering carefully recently the generation of randomized, representative test data for a test case I’m working on. I will blog the worked test case as well, but in the mean time I thought it worth jotting down a few ideas about generating reasonably representative volumes of test data for Oracle. My problem is that I want to model a particular growth pattern of data, namely that from a social network, and particularly I want to attempt to see how a sensible database design would scale for this network. To that end I want to model the network with a few hundred users – as one might see in a corporation, a few tens of thousands of users – as one might see when the network starts to take off, and finally with hundreds of thousands of users (I don’t have access to a suitable test infrastructure for millions of users). I then want to look at how some of the underlying queries scale. This blog offers some ideas on how to generate reasonable test data at arbitrary scales.

Modelling

A social network is defined (by Wikipedia 20 April 2011) as

A social network service essentially consists of a representation of each user (often a profile), his/her social links, and a variety of additional services

For our model, loosely based on www.digg.com as described here ), we will model 4 entities. These are described below:

Users

These are people that join the service. I have modelled these using a “users” table

Name                                      Null?    Type
----------------------------------------- -------- -----------------------
USERID                                    NOT NULL NUMBER(11)
USERNAME                                           VARCHAR2(15)
REGISTERED                                         DATE
PADDING                                            CHAR(50)

User id is a sequential number, username I can keep short and generate artificially , registered is the date the user account was created and padding is used to keep row lengths longer (to model other data being required in a real design)

Friends

These are the people that users choose to link to, the social links described in the wikipedia definition. This is modelled as shown below

Name                                      Null?    Type
----------------------------------------- -------- -----------------------
ID                                        NOT NULL NUMBER(10)
USERID                                             NUMBER(10)
USERNAME                                           VARCHAR2(15)
FRIENDID                                           NUMBER(10)
FRIENDNAME                                         VARCHAR2(15)
MUTUAL                                             NUMBER(1)
DATE_CREATED                                       DATE

ID is again a meaningless key. Userid is the user creating the link, friendid is the target of the link, mutual we don’t use, and date created the date the link was created. This table is drawn from the same link as above. It’s interesting to note that the datatypes for the id columns differ in length but for our purposes in Oracle that will not matter.

Items

This is a table whose existence I have surmised and is intended to contain all items added to our social network. For this work it represents interesting items added by users. It is defined as

Name                                      Null?    Type
----------------------------------------- -------- -------------------
ITEMID                                    NOT NULL NUMBER(11)
USERID                                             NUMBER(11)
DUGDATE                                            DATE
PADDING                                            CHAR(50)

Again item id is a meaningless primary key, userid is the id of the user who added it. Dugdate a date on which the item was ‘dug’ – we don’t use this – and padding to plump out any extra columns.

Diggs (sic)

This is a table described by digg in the blog article above and which has the following definition

Name                                      Null?    Type
----------------------------------------- -------- -----------------------
ID                                        NOT NULL NUMBER(11)
ITEMID                                             NUMBER(11)
USERID                                             NUMBER(11)
DIGDATE                                            DATE

This table again represents a user interaction, just as friends does, namely the act of “digging” an item added to the site. Again the datatypes have that odd length difference. It’s clear from the blog entry that the id columns are primary key values generated in a meaningless way.

Problem

The problem that I have is that I want to model reasonably representative generated data. For a social network however randomly generated data – using dbms_random.value or dbms_random.normal won’t be representative. We can make the following assumptions about our putative site.

This means that I want to be able to generate my registration dates so that they are distributed exponentially, my friends per user using a power law and the number of diggs per user such that it fits a poisson distribution. In general when considering how to model your systems it’s worth bearing in mind that data often does not follow normal or uniform distribution patterns. Changing the distribution may well cause behavioural changes and oddities – particularly if you are operating on a system prior to 11g that may not estimate cardinality well

Possible Solutions

Ideally of course I’d like to generate all the data in oracle at different scales , I’m going to choose 500, 5000, 50000 and 500000 users. For all but one of the problems described above there is a ready Oracle solution, for the distribution of diggs amongst users a bit of lateral thinking is required. First the easy part, if we assume that the number of friends follows a power law. We can produce a distribution of links for testing using the following (inefficient) code extract.

DECLARE
  l_usercount constant NUMBER := 500000;
  l_itemcount constant NUMBER := 5000000;
  l_username users.username%type;
  l_friendcount NUMBER;
  type friendlist IS TABLE OF pls_integer;
  l_friendlist friendlist;
  l_itemid NUMBER;
  l_userid NUMBER;
BEGIN
    -- Setup friend relationships. Power law.
    FOR i IN 1..l_usercount
    LOOP
      -- initialize array
      l_friendlist := friendlist();
      -- get number of links for this users (1-100 distributed)
      l_friendcount := POWER(100, dbms_random.value) ;

      SELECT
        username
      INTO
        l_username
      FROM
        users
      WHERE
        userid = i;
      -- add friends
      FOR j IN 1..l_friendcount LOOP
          INSERT INTO friends
(userid , username , friendid , friendname , date_created )
          SELECT
            i , l_username , userid , username , sysdate - dbms_random.normal*dbms_random.value(1,365)
          FROM
            users
          WHERE
            userid = l_friendlist(j);
EXCEPTION
        WHEN dup_val_on_index THEN
          NULL;  -- occasionally dbms_random will get the same friend
        END;
      END LOOP;
      COMMIT;
      l_friendlist := NULL;
    END LOOP;
END;
/

For the number of diggs per user and the registration dates I found by far and away the easiest solution was to pre-generate a table of values that followed these distributions using the Excel Analysis Tool-Pak http://office.microsoft.com/en-us/excel-help/about-statistical-analysis-tools-HP005203873.aspx This tool allows you to generate numerical values that follow the described distributions, and excel’s save as csv feature allows you to easily create a file that can be loaded into the database via an external table. In my test setup I called the resultant table random_values and can populate my data using the following pseudo-code. I’ll look to publish the results of my investigations in the next blog entry but 1000 words is enough for a blog, and the principle that your test data should reflect reality however that looks is independent of the application that you are testing.

BEGIN
      FOR i IN 1..l_usercount
      LOOP
        -- dig n items our table assumes 2.8 per user
        SELECT
          poisson
        INTO
          l_digs
        FROM
          random_values
        WHERE
          userid = i;
        FOR n   IN 1..l_digs
        LOOP
          l_itemid := floor(dbms_random.value(1,l_itemcount)); -- what do I dig
          INSERT
          INTO
            diggs
            (
              itemid,
              userid,
              digdate
            )
            VALUES
            (
              l_itemid,
              i,
              sysdate - (dbms_random.normal*dbms_random.value(1,365))
            );
        END LOOP;
      if mod(i,10000) = 0 then commit; end if
      END LOOP;
   commit;
    END ;

Possibly Related Posts:

  • No Related Posts found

Written by Niall Litchfield

May 3rd, 2011 at 2:33 pm

Pop-Up Blockers

with 3 comments

I’m not a fan of pop-up ads at all. This is quite a common position on the web and first led to the development of add-ins to popular browsers to prevent these being displayed and then to the browsers themselves blocking pop-ups.

Something quite odd seems to have happened with Internet Explorer 9 however, when it blocks a pop-up, which it will do by default, it produces a dialog box window (in a brand new UI design style) at the bottom of the window telling me what it has done and prompting me to allow pop-ups once for this site or else via the “more options” link to always allow pop-ups for this site.

Now correct me if this seems unreasonable to you, but I would have thought that the mere fact that a user had enabled a pop-up blocker would suggest to whoever the UI designer was for this feature that maybe, just maybe displaying an unexpected window over the top of the web page the user was browsing in order to claim their attention was perhaps not the single best design for a tool aimed at preventing unexpected windows appearing over the top of the web page users are browsing in order to claim their attention.

Possibly Related Posts:

  • No Related Posts found

Written by Niall Litchfield

April 18th, 2011 at 1:01 pm

Posted in Uncategorized

Tagged with ,