Register to post in forums, or Log in to your existing account
 

Play RetroMUD
Post new topic  Reply to topic     Home » Forums » CMUD General Discussion
Progonoi
Magician


Joined: 28 Jan 2007
Posts: 430

PostPosted: Thu Aug 07, 2008 2:43 pm   

%mapfilter vs. %mapquery vs. direct COM approach
 
Now, bear with me, heh.

Have been doing speed comparisons towards 3 separate routes of data look-ups over last couple of days.

I know that once Map database goes completely into SQL and all the bugs will be ironed out, all this (least the COM aspect) will be moot, but...

Until now I've used %mapfilter(%concat collaboration to #loop %numrooms into a DB list from where I choose one I want to run to (within one Zone).

Code:

#call %mapfilter(%concat("Name"," LIKE ","'%",%replace(@RoomSearch,"'","''"),"%'"," AND ","ZoneID"," = ",%zonenum))
#loop %numrooms {#addkey RoomDB {%roomvnum( %i)} {%i}}


Using this exact bit of code, speeds differ from ca. 200 ms to around 1400 depending how many close enough rooms will be loaded into DB. Of course, fewer they are, faster it gets.

Yesterday I did some general tests, using %mapquery and %concat. I'm not very familiar with SQL type lookups so only the most
general ones I was able to complete successfully.

Either way, it seemed that speed difference between %mapfilter and %mapquery is more or less the same.

Today I started doing map DB wide lookups - entering a partial room name and by using COM approach, getting the Zone(s) that have a room(s) like the one I asked for.

I used Zafusteria's code from ZMud finished scripts section.

Code:

#local $secs
$secs=%secs
#show Aeg enne: $secs
#VARIABLE Conn %comcreate( "ADODB.Connection")
#CALL @Conn.Open( "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=E:\zMUD\user\maps\maps\map.mdb")
#IF (@Conn.ConnectionString ="") {
  #SHOW "could not open connection to database"
  #ABORT
  }
#VARIABLE rs @Conn.Execute( %concat( "SELECT z.name, o.name FROM ObjectTbl o, ZoneTbl z WHERE o.name LIKE '%", %-1, "%' and o.zoneid = z.zoneid ORDER BY z.name, o.name"))
#ECHO @rs.GetString
$secs=%secs-$secs
#show Aeg p2rast: $secs
#CALL @rs.Close
#VARIABLE rs ""
#VARIABLE Conn ""


The outcome was amazing. Partial room names such as castle or forest or such which relative number of existence is amount-wise several pages was returned with 50-500ms. Like, wow!

However, the code above makes Map DB search using all the data map db contains. Very sweet, but not something I'd need on regular basis.

What I'm looking for is using the same COM approach but for the same purpose my %mapfilter code above serves. I need list of rooms close to the partial query returned and put into DB.

EDIT: Perfect would be if gathered "matches" are returned as roomvnums. If its even possible with COM. In that case they can be used via #walk without any additional steps.

Pretty sure I was confusing, so if anyone feels that he can help, feel free to ask for more and I'll try to answer.

Thanks in advance,

Prog


Last edited by Progonoi on Tue Aug 12, 2008 3:06 pm; edited 1 time in total
Reply with quote
Vijilante
SubAdmin


Joined: 18 Nov 2001
Posts: 5182

PostPosted: Thu Aug 07, 2008 9:02 pm   
 
Step 1. Get my Toolbox from the package library. It has some predefined queries for various things, autmatically links to your map, and will give you quite a few examples of how to do things.

Step 2. Start writing you own queries. For example the correct way to do the query above is with a JOIN; while the way it is works the JOIN will produce results faster.
_________________
The only good questions are the ones we have never answered before.
Search the Forums
Reply with quote
Progonoi
Magician


Joined: 28 Jan 2007
Posts: 430

PostPosted: Thu Aug 07, 2008 9:15 pm   
 
Well, I'm still pretty much in the process of getting myself familiar on a more deeper level with the program until
I choose to eventually buy it (which I most likely will but not a jump the gun sort of type and hence still having few weeks left).
I'm sure though that once I've bought it, package library will become my next best friend.

Can you point me to some help material about queries such like these perhaps? It took me quite a while to understand the mechanics of
queries while using %mapfilter(%concat but finally I understood it, most of it anyway. Doing more exact and complex queries into
Map DB itself is something pretty new to me.

Thanks,

Prog
_________________
The Proud new owner of CMud.

--------------------------------
Intel Core i5-650 3,2GHz
4 DD3 RAM
GTX 460 768MB
Win 7 Home Premium 64x
--------------------------------
Reply with quote
Seb
Wizard


Joined: 14 Aug 2004
Posts: 1269

PostPosted: Fri Aug 08, 2008 2:53 am   
 
So you basically want
AND ","ZoneID"," = ",%zonenum
added to the COM query?
Reply with quote
Progonoi
Magician


Joined: 28 Jan 2007
Posts: 430

PostPosted: Fri Aug 08, 2008 3:00 pm   
 
Basically, thats true.

Spent few hours last night, reading through SQL Database Tutorial I found on internet and I must say that most likely I'd be able to do
queries I need based on what I learned, but what I've never completely understood is the usage of %concat in the COM script above.

Can't I do something like

SELECT z.name FROM ObjectTBL WHERE o.name LIKE '%", %-1, "%' AND ","ZoneID"," = ",%zonenum

instead?

Sorry for coming across dumb, but I haven't put too much serious thought into direct queries such like these before.
All I've used so far is the easy setup I had with %mapfilter.


Prog
Reply with quote
Rahab
Wizard


Joined: 22 Mar 2007
Posts: 2320

PostPosted: Fri Aug 08, 2008 7:51 pm   
 
%concat() just takes several things and puts them together into one long string. Often, you can assume that Cmud will automatically put pieces of string together into a single large string, but Cmud does not guarantee that. Using %concat() simply ensures that it happens. I think that %mapquery() may be one of the functions that does not always automatically concatenate strings. In any case, it never hurts to use %concat() to put strings together, and is much more robust. When in doubt, use %concat() to be sure.
Reply with quote
Seb
Wizard


Joined: 14 Aug 2004
Posts: 1269

PostPosted: Mon Aug 11, 2008 9:16 pm   
 
So it probably becomes something like this:
Code:
...(other code the same as the 2nd code block in this thread)
#VARIABLE rs @Conn.Execute( %concat( "SELECT name FROM ObjectTBL WHERE name LIKE '%", %-1, "%' AND ","ZoneID"," = ",%zonenum))
...

I don't know why Vijilante suggested you should use a JOIN: there's only one database table involved!
Reply with quote
Progonoi
Magician


Joined: 28 Jan 2007
Posts: 430

PostPosted: Mon Aug 11, 2008 9:25 pm   
 
Sweet! Yeah, when I read through some web tutorial for SQL Queries few days ago the impression I got was that JOIN is used when there's
more than one table needed.

The thing is, I think I understood the tutorial pretty well. Strangely, where I have always had problems is forming a correct %concat like you have above. Though, the basic principle you use above seems to be same as I've used in my original %mapfilter query on first glance, hmm... Maybe I'm just panicking too much Confused

Meanwhile I'll try it out and post speed results in case anyone's interested.

Thanks Seb.

EDIT: Started incorporating all this into code and one thing got me thinking. The original script takes the mapfilter, gets matching data, and as you've already set the current zone by it, you can do #loop %numrooms and parse the data. Can't something like this be done with this setup as well, for example, couldn't I use ORDER BY ObjID to get roomvnums and then somehow parsing them into a db?
I'm just bursting out ideas here, heh.

EDIT #2: Basically if I'd be able to get the data by roomvnums, I should be able to make a new string list and use that one for the actual walking. Something like, walk_list=@rs.GetString. Wouldn't it work?

Prog
Reply with quote
Seb
Wizard


Joined: 14 Aug 2004
Posts: 1269

PostPosted: Mon Aug 11, 2008 10:55 pm   
 
Progonoi wrote:
Strangely, where I have always had problems is forming a correct %concat like you have above. Though, the basic principle you use above seems to be same as I've used in my original %mapfilter query on first glance, hmm... Maybe I'm just panicking too much Confused

Meanwhile I'll try it out and post speed results in case anyone's interested.

Thanks Seb.

EDIT: Started incorporating all this into code and one thing got me thinking. The original script takes the mapfilter, gets matching data, and as you've already set the current zone by it, you can do #loop %numrooms and parse the data. Can't something like this be done with this setup as well, for example, couldn't I use ORDER BY ObjID to get roomvnums and then somehow parsing them into a db?

Yeah, all I did was merged your three code snippets. Wink %concat is actually very simple, but it does have a bit of a twist in that it can take any number of arguments (and just concatenates them all).

I'd be interested in the speed result.

I'm pretty sure you can put the results into a db, but off the top of my head I'm not sure how.
Reply with quote
Progonoi
Magician


Joined: 28 Jan 2007
Posts: 430

PostPosted: Tue Aug 12, 2008 3:05 pm   
 
Well, I haven't figured out how to parse the data got by COM into a db nor have I really had time to.

However just now I made some speed tests. Results are astonishing.

Code:

#local $secs
  RoomSearch=%1
  $secs=%secs
  #show Time before look-up: $secs
  #call %mapfilter(%concat("Name"," LIKE ","'%",%replace(@RoomSearch,"'","''"),"%'"," AND ","ZoneID"," = ",%zonenum))
  $secs=%secs-$secs
  #show Time after look-up: $secs


This code came down to 69ms/72ms/72ms/71ms avr *71 ms* doing the same look-up 4 times in a row.

Code:

VARIABLE Conn %comcreate( "ADODB.Connection")
#local $secs
$secs=%secs
#show Aeg enne p2ringut: $secs
#CALL @Conn.Open( "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=E:\zMUD\user\maps\maps\map.mdb")
#IF (@Conn.ConnectionString ="") {
  #SHOW "could not open connection to database"
  #ABORT
  }
#VARIABLE rs @Conn.Execute( %concat( "SELECT name FROM ObjectTBL WHERE name LIKE '%", %-1, "%' AND ","ZoneID"," = ",%zonenum))
$secs=%secs-$secs
#show Aeg p2rast p2ringut: $secs
#ECHO @rs.GetString
#CALL @rs.Close
#VARIABLE rs ""
#VARIABLE Conn ""


But this one came down to: 16ms/12ms/11ms/10ms avr. *12,25 ms*!!!!

This is almost *6 times* faster (Well, rounded down to 5.8 to be exact)

Prog
Reply with quote
Seb
Wizard


Joined: 14 Aug 2004
Posts: 1269

PostPosted: Tue Aug 12, 2008 7:02 pm   
 
When doing database queries like this, e.g. the SQL one since that is an actual query, you should generally take the *first* result as your time (so 16ms). If you repeat the query, the data is cached, so it's hardly a valid timing test. If you want to repeat the timing test, you'll probably need to close CMUD and reopen it, or do whatever to make sure your query you are just about to test isn't cached. Also, it's worth reversing the order of your tests. So if you tested %mapfilter first, it might be slower than if you tested it afterward the other methods. So when comparing database queries for speed I often run them first one way round and then the other way round (and then one may be able to average two results).

Bear in mind also that the first code block is also doing a %replace. That won't have any noticeable affect on the times, but you should also do this in the second code block or any single quotes in your %-1 parameter will not be escaped properly and the query will not work the way you want (or at all). Also, I haven't seen any timings with %mapquery... That should be more of a half-way house between these two, in terms of what it does (I would guess).
Reply with quote
Zugg
MASTER


Joined: 25 Sep 2000
Posts: 23379
Location: Colorado, USA

PostPosted: Tue Aug 12, 2008 7:37 pm   
 
The %mapfilter is creating a "filter" on the existing map database. In Delphi we have things called "DataSets" that you can apply a filter to. So the Dataset is filled with "SELECT * FROM ObjectTbl" and then %mapfilter applies a filter to the result. This is always going to be slower than a direct SQL query. The %mapfilter is not intended for full speed...it is intended for convenience because then you can use %numrooms etc to loop through the rooms in the remaining filter set.

Keep in mind that the database format is changing in v3.0. So if you write scripts that use ADO COM objects, then all of your scripts will break in v3.0+. On the other hand, a filter of an SQLite database is much faster than a filter of an ADO database in Delphi.

So unless the speed difference is critical to your script, you should never be accessing the map database with low-level COM objects unless you want to spend all of the time rewriting them for the new CMUD versions. And since you cannot create COM objects for SQLite, you'll need to use Lua to perform the low-level access. This means that rewriting your scripts will not be trivial.
Reply with quote
Seb
Wizard


Joined: 14 Aug 2004
Posts: 1269

PostPosted: Tue Aug 12, 2008 7:54 pm   
 
That's what I thought Zugg, but I hoped you'd confirm my suspicions about filtering a DataSet... Smile %mapquery seems like it should be faster because it's not doing that filtering, and it shouldn't break with the upgrade to v3.0+ (hence why I suggested he show me the timings).
Reply with quote
Progonoi
Magician


Joined: 28 Jan 2007
Posts: 430

PostPosted: Tue Aug 12, 2008 8:50 pm   
 
With all due respect, even though my speed tests were unorthodox, for me it seems reasonable to assume, based on the numbers I saw, that at this very moment, direct COM object query is a lot more faster than using %mapfilter.

Deeper explanation is really appreciated though. While I'm a really lazy person I had a doubt anyway for going through with re-writing this particular script using COM (plus I still haven't come up with a way to parse the data into DB, heh).

It just seemed interesting to me, that they have such speed difference in comparison. Sad that I discovered it way too late, though (because as you said, Zugg, %mapfilter will be faster regardless in the future anyway).

Anyway, thanks for clearing this up.


EDIT: Heh. Seb, I suppose I could re-write my stuff using %mapquery then. Though when I did some general kind of speed tests between %mapfilter and %mapquery, the latter seemed to have pretty much same speed if not slower. But I guess using that I might at least do something right in time for future Confused

Prog
Reply with quote
Display posts from previous:   
Post new topic   Reply to topic     Home » Forums » CMUD General Discussion All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

© 2009 Zugg Software. Hosted by Wolfpaw.net