Re: [Modeling-users] Lazy Initialization Part 2
Status: Abandoned
Brought to you by:
sbigaret
From: Sebastien B. <sbi...@us...> - 2003-07-10 22:01:44
|
Hi, 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. > 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). I understand this, but this is not that simple. See below. > 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. I will think about it; but as you already noted it, this can result in unwanted cascaded fetchs ultimately loading the whole db. > So my question is : Is it possible to do so ? 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: [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 Now consider the to-many relationship: >>> 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 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. As a conclusion, I'll say that: - either fetch all the i18ns objects, then pre-fetch the inverse to-one pointing to your record objects, - 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). If you could try both, I'd be very interested in knowing how long each one takes with your data. Thanks in advance! 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. > BTW The trick with FixedPoint works really well, tanks for the hints ! Glad to hear this, this will be then documented for the next release. -- S=E9bastien. |