Any clever coders out there

Peterg
Posts: 62
Joined: Mon Nov 28, 2005 5:36 pm
Location: Oxford UK
Contact:

Any clever coders out there

Post by Peterg »

Hi all

I have a function which seeks for a price in a table which can have upto 64 different combinations. As a result of this there are 64 seeks per find
which is quite fast in dbf but horribly slow in sql.

Can anyone suggest a better way for writting this function.

I will pay for any good ideas

Thanks
Peter

code is

FUNCTION find_price(sp_site,sp_acc,sp_sit,sp_con,sp_was,sp_reg,sp_eff,sp_ctype,sp_disp)
LOCAL element := {"","","","","",""}
LOCAL alldone := .F.
LOCAL binary := 63
LOCAL old_area := SELECT()
PRIVATE element1,element2,element3,element4,element5,element6,spsite
spsite := sp_site
SELECT SKIPPRIC
DO WHILE !alldone .AND. binary >= 0
element1 := IF(LAND(32,binary),sp_acc,SPACE(10))
element2 := IF(LAND(16,binary),sp_sit,SPACE(10))
element3 := IF(LAND(8,binary),sp_ctype,SPACE(10))
element4 := IF(LAND(4,binary),sp_was,SPACE(10))
element5 := IF(LAND(2,binary),sp_reg,SPACE(10))
element6 := IF(LAND(1,binary),sp_disp,SPACE(10))
SKIPPRIC->(SR_SETFILTER("site_id="+STR(spsite)+" and sp_contain='"+Alltrim(sp_con)+"'"))

IF SKIPPRIC->(DBSEEK(STR(sp_site,2,0)+element1+element2+element3+sp_con+element4+element5+element6))

DO WHILE SKIPPRIC->SITE_ID == sp_site .AND. ;
SKIPPRIC->SP_CUSTNO == element1 .AND. ;
SKIPPRIC->UNIQ_NBR == element2 .AND. ;
SKIPPRIC->SP_CUSTYPE == element3 .AND. ;
SKIPPRIC->SP_CONTAIN == sp_con .AND. ;
SKIPPRIC->SP_WASTE == element4 .AND. ;
SKIPPRIC->SP_REGION == element5 .AND. ;
SKIPPRIC->SP_DISPSIT == element6 .AND. ;
!SKIPPRIC->(EOF())
IF ((SKIPPRIC->SP_DELDATE >= sp_eff .OR. ;
SKIPPRIC->SP_DELDATE == CTOD("")) .AND. ;
SKIPPRIC->SP_EFFDATE <= sp_eff)
alldone := .T.
EXIT
ENDIF
SKIPPRIC->(DBSKIP())
ENDDO
ENDIF
IF !alldone
--binary
ENDIF
ENDDO
SELECT(old_area)
RETURN alldone[
User avatar
Roger Seiler
Posts: 223
Joined: Thu Dec 01, 2005 3:34 pm
Location: Nyack, New York, USA
Contact:

Post by Roger Seiler »

How about using arrays for this?

At the beginning of the work session, you could load the data from SKIPPRIC into a separate array for each database field, and then using ASCAN() your lookups should be lightning fast, even with SQL.
User avatar
James Bott
Posts: 4654
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA
Contact:

Post by James Bott »

Peter,

Can you provide a small self-contained program with the DBF and some example calls to the function and the proper results? This would allow us to test it and try to improve the speed.

James
User avatar
James Bott
Posts: 4654
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA
Contact:

Post by James Bott »

Roger,

I think the problem is that the array has to be built for each call to the function, not per worksession (I am assuming "worksession" is each time the application is run). Still it might be faster.

James
User avatar
Antonio Linares
Site Admin
Posts: 37481
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Post by Antonio Linares »

Peter,

As you mention, the delay comes from the 64 seeks.

Don't do 64 seeks: Use just one SQL query sentence.
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Roger Seiler
Posts: 223
Joined: Thu Dec 01, 2005 3:34 pm
Location: Nyack, New York, USA
Contact:

Post by Roger Seiler »

James,

From Peter's data, it looks as though his pricing factors, though complex, are actually constants. In his pricing function, it seems that the price for a given situation is determined by the interrelation between the specifics of the case and all of the constants involved in his pricing factors. If so, he should only have to build the arrays once during a worksession, and then refer to the arrays each time he calls the pricing function, thereby avoiding the slow disk seeks. But if the pricing factors themselves are variables within the scope of a worksession, then you're right, the arrays approach definitely won't work.

- Roger
User avatar
James Bott
Posts: 4654
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA
Contact:

Post by James Bott »

Roger,

You are correct--there are a number of constants, and it is not clear exactly what he is doing.

Antonio may be correct in that one SQL statement would probably do it. But without really understanding how the search works it is hard to tell.

James
User avatar
xProgrammer
Posts: 464
Joined: Tue May 16, 2006 7:47 am
Location: Australia

Post by xProgrammer »

Hi all

I think that we can only really offer the best advice if peterg gives an explanation of what his code needs to achieve, how often and when the data changes and the nature of the environment in which this needs to be achieved (eg single PC, LAN or WAN and if WAN what sort of speed)

Maybe then an appropriate index (if we are to stay with xBase tables) would mean that 64 seeks would not be required and / or setfilters would not be required. Maybe we can use arrays / hashes. Maybe the pricing table can be cached in memory so table access isn't required at all.

SQL can be much more efficient with multiple seeks across a slower link but on a local PC xBase table access using indices can be very efficient.

Regards
xProgrammer
Peterg
Posts: 62
Joined: Mon Nov 28, 2005 5:36 pm
Location: Oxford UK
Contact:

Post by Peterg »

Hi all
Firstly how do I upload a sample prg and dbf for testing?

The price file could be very large > 150K records and could be updated by any number of users during the course of the day so cerating an array is probably not possible.

A price can exist for the following
site (internal identifier)
customer type (a group of customer)
customer
delivery location
container
waste type
disposal lcoation
haulier
date

or any combination of the above with the container being the common factor.
The system has to try and find the best possible match before reporting that there are no prices setup. In dbfs this works lightning fast so is not a problem but in sql 64 seeks take way too long

Any ideas
Peter
User avatar
Antonio Linares
Site Admin
Posts: 37481
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Post by Antonio Linares »

Peter,

Try to build a SQL query that does it all.

Even if you can't, please start writting it here so we can help you, once we understand the exact query that you need
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
xProgrammer
Posts: 464
Joined: Tue May 16, 2006 7:47 am
Location: Australia

Post by xProgrammer »

Hi Peter

If your SQL code pretty much follows your xBase code it will be inefficient. SQL is efficient where you "bundle up" the work into a single query. If you have a series of individual "seeks" SQL will be inefficient compared to xBase on a local machine.

From what I can see of your case if you need to use SQL you probably need to use a stored procedure. These can be precompiled on many vendor implementations and can be very fast.

Whilst I have used SQL in one major project, I am no expert and am not the right person to help you with writing a suitable stored procedure. They do exist although this may not be the best forum to locate them in.

I don't know how familiar you are with stored procedures. You could start with:

http://en.wikipedia.org/wiki/Stored_procedure
http://msdn.microsoft.com/en-us/library/aa174792.aspx
http://www.sql-server-performance.com/a ... cs_p1.aspx
http://databases.about.com/od/sqlserver ... cedure.htm
http://www.informit.com/articles/article.aspx?p=25288

The following article outlines some techniques that you may find to be of use.

http://vyaskn.tripod.com/passing_arrays ... edures.htm

And maybe consider registering on

http://searchsqlserver.techtarget.com/l ... %2C00.html

Regards
xProgrammer
Peterg
Posts: 62
Joined: Mon Nov 28, 2005 5:36 pm
Location: Oxford UK
Contact:

Post by Peterg »

I am not sure where to start but here goes

variable declarations
mSiteID = 1
mCustacc = "ABC123"
mUniqnbr = "0000000001"
mCustType = "EXTERNAL"
mContainer = "1100WB"
mWaste = "GENERAL"
mDisposer = "XYZ987"
mDate = DATE()


select * from skippric
where site_id = mSiteID and sp_custno = mcustacc and uniq_nbr = mUniwnbr and sp_contype = mContainer and sp_waste = mWaste and
sp_effdate<=mDate

but if this fails then it should test for all other combinations until there is nothing left to test.

Once it finds a record then i can use the prices contained in this record

Does that help?

Peter
User avatar
Antonio Linares
Site Admin
Posts: 37481
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Post by Antonio Linares »

Peter,

Use OR to check for the other combinations from the same SQL sentence
regards, saludos

Antonio Linares
www.fivetechsoft.com
Peterg
Posts: 62
Joined: Mon Nov 28, 2005 5:36 pm
Location: Oxford UK
Contact:

Post by Peterg »

Antonio
This will result in 64 seperate or statements. Do you think this will be faster

Peter
User avatar
James Bott
Posts: 4654
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA
Contact:

Post by James Bott »

Peter,

Can you design your query so that it returns all possible matches to a recordset, then scan the recordset for the best match?

James
Post Reply