Re: Eaten by the Tiger? Open Source WO is coming...
Alex Raftis <[email protected]> Wed, 31 Aug 2005 08:18:12 -0500
| Newsgroups | gmane.comp.web.webobjects.general |
|---|---|
| Message-ID | <[email protected]> |
On Aug 25, 2005, at 11:22 AM, Pierce T. Wetter III wrote: > Which makes AJR much superior to EOF, as I commented, since EOF > uses NSArrays, and the last object is definitely not as fast as the > first object. > > I don't know where I got that AJR used NSArrays then, because I > remember reading the header file for an EOEditingContext.h and > seeing NSArray, and going "bummer" and moving on. > > So I apologize, and I'm much happier with AJR now. :-) > > Just out of curiousity, do you have any idea what the ratio of EOF > overhead to database fetch time is? We found that it was 3x, that > it took 3 times as long to fetch an object into EOF as it did to > fetch raw rows from Frontbase. Some of that was building the > objects (malloc, etc.) but a lot of it was registering the objects. OK, here's a little about how EOF does work. In EOF, the editing context does in fact use NSMutableSet for it's backing store. Yes, the method -insertedObjects, -updatedObjects, and -deletedObjects return an NSArray, but the array is only constructed (and cached) when the above calls to those methods are made. So, EOF will not inherently slow down as more objects are fetched into the editing context. However, both EOF and AJRDatabase make use of an optimization for objects that have integer (or long) primary keys. For EOF, they have a class called _EOIntegralPrimaryKey and AJRDatabase has a class called EONumericGlobalID. Yeah, they're different, but very low level and not used by the high level API's. The idea behind both these classes is that you can created a faster, more efficient global ID for objects that basically use an integer as their primary keys. Since in DB design, the vast majority of tables do use integers for their primary keys, this works out pretty well. However, there's a problem with this. If you insert 100,000 (this was my test case) objects into a hash table (at least Apple's hash tables) where the hash function is basically linear, you'll find that performance serious begins to degrade. It appears that what happens is that very few buckets in the hash table are used, which basically results in a hash table with performance not all that much better than an array. To compensate for this, AJRDatabase perturbs it's hash value in such a way that the values will never be linear. I had assumed that EOF would do the same, but from the slow downs other people have described, I'm going to assume that whatever perturbation they do isn't sufficient to produce non-linear or near non-linear results. If anyone's really curious, AJRDatabase basically calls srandom (pkValue) followed by hash ^= random(). This produces very non-linear results over large data sets. For example, in my test case, with 100,000 records, before I added the random function, I saw serious degradation of performance in the hash functions. So much so that is took multiple minutes for fetch the 100,000 records. After the change, AJRDatabase could fetch that many records in a fraction of the time. Basically, the last records fetched as fast as the initial records. As a final note, this code will need to be updated a little bit once AJRDatabase supports full multithreading, since the key is relying on the behavior of random number generators to produce the same series of pseudo random numbers given the same initial seed. The problem, of course, is that if another thread calls random() between my call to srandom() and random(), we'll be one or more values down the sequence and thus won't produce the same hash key. I hope this helps clarify what's going on under the hood in EOF and AJRDatabase. Alex Raftis --- [email protected]