Re: [Modeling-users] Lazy Initialization Part 2
Status: Abandoned
Brought to you by:
sbigaret
From: Sebastien B. <sbi...@us...> - 2003-07-11 11:11:06
|
A quick note about this: I wrote it a bit too quickly yesterday. Even w/ to-one rel., you'll still have to pay for the extra round-trip to the db when accessing the inverse to-many rel: >>> ec=3DEditingContext() >>> objs=3Dec.fetch('Book') # fetch all books >>> gids=3D[o.globalID() for o in objs] >>> pks=3D[gid.keyValues()['id'] for gid in gids] >>> objs[0].getAuthor().isFault() >>> 1 >>> ec.fetch('Writer', 'books.id in %s'%pks) # all fetches at once >>> objs[0].getAuthor().isFault() # no round-trip to the db >>> 0 >>> objs[0].getAuthor().getBooks() # additional round-trip to the db ...for the very same reason I explained in the previous post. I'm thinking of a way to avoid this, but will probably no have the time until tuesday to test and code it.=20 In the meantime, as I said, I'm quite interesting in hearing from the performance you observe w/ your db when prefetching the rels. and setting MDL_PERMANENT_DB_CONNECTION to 1. -- S=E9bastien. Sebastien Bigaret <sbi...@us...> writes: > Hi, >=20 > Here are some hints; sorry, but I can't spend a lot of time on this > for now. BTW I will be quite busy until tuesday, probably mostly > offline. >=20 > > I have a particular record set that hold 700 or so rows. I use > > dynamic i18n from another table that we will call i18nTable for > > simplicity. There is only a few fields in i18nTable : title and > > description.=20=20 > >=20 > > The relation look like this :=20 > [snipped: toMany rel. 'i18ns'] > > So here I am trying to fetch my whole record set. The initial fetch > > is really fast but when I try to getI18ns() on each fetched object it > > result in a SQL SELECT. This mean that do 701 SELECTs where I > > intended to do only one... My whole fetch take 30 seconds to complete > > but the initial fetch (the master records with lots of columns) take > > barely a second. It would be really nice if I could group the fetch so > > that it resulted in a single SQL select (ok, maybe 2 : one for master > > records, one for all the i18ns). >=20 > I understand this, but this is not that simple. See below. >=20 > > I understand why you really want lazy initialization. It's would be > > even slower to fetch all the database when you fetch an object with > > many relations. But having it optional, something like a > > recursiveFecth() would be really nice. >=20 > I will think about it; but as you already noted it, this can result in > unwanted cascaded fetchs ultimately loading the whole db. >=20 > > So my question is : Is it possible to do so ? >=20 > Before adressing your particular pb., let's see of this can be done with > a to-one relationship. In fact, a simple combination of globalIDs and > the operator 'in' makes the trick: >=20 > [in Modeling/tests/testPackages] > >>> from Modeling.EditingContext import EditingContext > >>> import AuthorBooks > >>> ec=3DEditingContext() > >>> objs=3Dec.fetch('Book') # fetch all books > >>> gids=3D[o.globalID() for o in objs] > >>> pks=3D[gid.keyValues()['id'] for gid in gids] > >>> objs[0].getAuthor().isFault() > 1 > >>> ec.fetch('Writer', 'books.id in %s'%pks) # all fetches at once > >>> objs[0].getAuthor().isFault() # no round-trip to the db > 0 >=20 > Now consider the to-many relationship: >=20 > >>> ec=3DEditingContext() > >>> objs=3Dec.fetch('Writer') > >>> gids=3D[o.globalID() for o in objs] > >>> pks=3D[gid.keyValues()['id'] for gid in gids] > >>> objs[0].getBooks().isFault() > >>> 1 > >>> ec.fetch('Book', 'author.id in %s'%pks) # all fetches at once > >>> objs[0].getAuthor().isFault() # still a fault! > >>> 1 > >>> len(objs[0]) # trigger a select >=20 > What is the pb here? The framework has no way to know that all necessary > objects for the given relation have been already loaded, so it needs to > fetch, at least to get the ids. So in this case there's no way to avoid > the additional round-trip to the db. However, these additional fetches > avoid the initialization phase for these objects (it's already done), so > you can expect these fetches to be significantly faster. >=20 > As a conclusion, I'll say that: >=20 > - either fetch all the i18ns objects, then pre-fetch the inverse > to-one pointing to your record objects, >=20 > - or stay as-is, and live w/ the additional fetches (where the > related i18ns are initialized by a single fetch, but where you'll > still get a fetch for each faulted array). >=20 > If you could try both, I'd be very interested in knowing how long each > one takes with your data. Thanks in advance! >=20 > Oh, and BTW: in case you've not already done it, you'd probably want > to set MDL_PERMANENT_DB_CONNECTION to 1, so that you do not pay the > additional overhead of closing and reopening the db connection for > each fetch. >=20 > > BTW The trick with FixedPoint works really well, tanks for the hints ! >=20 > Glad to hear this, this will be then documented for the next release. >=20 > -- S=E9bastien. |