|
View:
New views
2 Messages
—
Rating Filter:
Alert me
|
|
|
Performance problems: some more ideasDear list,
continuing on our earlier performance problems which we told you about a month or two ago, we have implemented the "loop inversion" for the spans that Artem proposed. The code is still a bit a proof of concept and not up to good coding standards yet, but I've appended the patches so you can have a look. Unfortunately, it shaved only a few percent off the time spent on our queries with spans. I'm now wondering why ObjectContext.GetObjects() first loads the SQL query results into a DataSet, and then calls FetchObjectsFromObjectTable() to again search within that DataSet using a loop and EvaluateWithObject() -- something the database server basically has already done for us. Our code spends extraordinary amounts of time inside FetchObjectsFromObjectTable(). I think it would make more sense to construct the result list inside FetchObjectsFromStore() itself. It would need a little extra administration, but I feel that that would easily outweigh the time which is IMHO now wasted. Is there any good reason why this is not done already? Maybe the call to DbDataAdapter.Fill() inside DbDataStore.FillTable() somehow adds unnecessary cruft into the DataTable that needs to be filtered out? Or am I missing something else? Any thoughts on this would be appreciated. Gerben Vos, ZyLAB Technologies. --- C:/Documents and Settings/Gerben/Local Settings/Temp/TCVb4fc.tmp/ObjectRelationBase.1.1.cs Tue Jun 12 16:21:46 2007 +++ C:/Documents and Settings/Gerben/Local Settings/Temp/TCVb4fc.tmp/ObjectRelationBase.1.2.cs Tue Aug 21 11:59:06 2007 @@ -240,6 +240,53 @@ Load(); } + public virtual IList HitSpansHelper(IList objects, string pathElement) { + if (innerList == null) { + + IList childObjects = Owner.Context.ObjectTable.GetObjects(foreignTableName); + + if(childObjects == null) { + return new ArrayList(); + } + + IList addedChildObjects = new ArrayList(); + foreach (IEntityObject childObject in childObjects) { + IEntityObject owner = Owner.Context.GetObjectFromTable( + Relation.ParentEntity.TableName, + new object[] { childObject.Row[foreignColumnName] } + ); + + if (owner == null) { + continue; + } + + addedChildObjects.Add(childObject); + ObjectRelationBase relation = (ObjectRelationBase)ObjectHelper.GetPropertyOrField(owner, pathElement); + if (relation.innerList == null) { + relation.innerList = new ArrayList(); + } + + relation.innerList.Add(childObject); + } + + foreach (IEntityObject eo2 in objects) { + object obj = ObjectHelper.GetPropertyOrField(eo2, pathElement); + ObjectRelationBase rel = obj as ObjectRelationBase; + + rel.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1)); + eo2.Context.RegisterForColumnChanges(new ColumnChangeHandler(OnColumnChanging), rel.foreignTableName, rel.foreignColumnName); + eo2.Context.RegisterForRowChanges(new RowChangeHandler(OnRowDeleting), rel.foreignTableName); + + if (rel.onListChanged != null) { + rel.Owner.Context.EntityObjectChanged += new EntityObjectChangedHandler(rel.OnEntityObjectChanged); + } + } + + return addedChildObjects; + } + return new ArrayList(); + } + public virtual void InvalidateCache() { if(innerList == null) --- C:/Documents and Settings/Gerben/Local Settings/Temp/TCV08dc.tmp/ObjectContext.1.1.cs Thu May 31 17:11:06 2007 +++ C:/Documents and Settings/Gerben/Local Settings/Temp/TCV08dc.tmp/ObjectContext.1.2.cs Tue Aug 21 12:56:56 2007 @@ -1369,31 +1369,40 @@ HitSpans(mainObjects, fetchSpec.Spans); } - private void HitSpans(IList objects, params string[] spans) - { + + private void HitSpans(IList objects, params string[] spans) { bool didIgnoreStore = ignoresDataStore; ignoresDataStore = true; - foreach(IEntityObject eo in objects) - { - foreach(string span in spans) - { + + ArrayList nonRelationSpans = new ArrayList(); + foreach(string span in spans) { + if (objects.Count > 0) { + IEntityObject eo = (IEntityObject)objects[0]; + string[] pathElements = span.Split(new char[]{'.'}, 2); - object obj = ObjectHelper.GetPropertyOrField(eo, pathElements[0]); - IList list = null; - ObjectRelationBase rel = obj as ObjectRelationBase; - if(rel != null) - { - rel.Touch(); - list = rel; - } - else - { - list = new object[] { obj }; - } - if(pathElements.Length > 1) + object obj0 = ObjectHelper.GetPropertyOrField(eo, pathElements[0]); + ObjectRelationBase rel0 = obj0 as ObjectRelationBase; + if(rel0 != null) { + IList list = rel0.HitSpansHelper(objects, pathElements[0]); + if (pathElements.Length > 1) { HitSpans(list, pathElements[1]); } + } else { + nonRelationSpans.Add(span); + } + } } + + foreach (string span in nonRelationSpans) { + foreach(IEntityObject eo in objects) { + string[] pathElements = span.Split(new char[]{'.'}, 2); + object obj0 = ObjectHelper.GetPropertyOrField(eo, pathElements[0]); + if(pathElements.Length > 1) { + HitSpans(new object[] { obj0 }, pathElements[1]); + } + } + } + ignoresDataStore = didIgnoreStore; } --- C:/Documents and Settings/Gerben/Local Settings/Temp/TCV08dc.tmp/ObjectContext.1.1.cs Thu May 31 17:11:06 2007 +++ C:/Documents and Settings/Gerben/Local Settings/Temp/TCV08dc.tmp/ObjectContext.1.2.cs Tue Aug 21 12:56:56 2007 @@ -1369,34 +1369,43 @@ HitSpans(mainObjects, fetchSpec.Spans); } - private void HitSpans(IList objects, params string[] spans) - { - bool didIgnoreStore = ignoresDataStore; - ignoresDataStore = true; - foreach(IEntityObject eo in objects) - { - foreach(string span in spans) - { - string[] pathElements = span.Split(new char[]{'.'}, 2); - object obj = ObjectHelper.GetPropertyOrField(eo, pathElements[0]); - IList list = null; - ObjectRelationBase rel = obj as ObjectRelationBase; - if(rel != null) - { - rel.Touch(); - list = rel; - } - else - { - list = new object[] { obj }; - } - if(pathElements.Length > 1) - HitSpans(list, pathElements[1]); - } - } - ignoresDataStore = didIgnoreStore; - } - + + private void HitSpans(IList objects, params string[] spans) { + bool didIgnoreStore = ignoresDataStore; + ignoresDataStore = true; + + ArrayList nonRelationSpans = new ArrayList(); + foreach(string span in spans) { + if (objects.Count > 0) { + IEntityObject eo = (IEntityObject)objects[0]; + + string[] pathElements = span.Split(new char[]{'.'}, 2); + object obj0 = ObjectHelper.GetPropertyOrField(eo, pathElements[0]); + ObjectRelationBase rel0 = obj0 as ObjectRelationBase; + if(rel0 != null) { + IList list = rel0.HitSpansHelper(objects, pathElements[0]); + if (pathElements.Length > 1) { + HitSpans(list, pathElements[1]); + } + } else { + nonRelationSpans.Add(span); + } + } + } + + foreach (string span in nonRelationSpans) { + foreach(IEntityObject eo in objects) { + string[] pathElements = span.Split(new char[]{'.'}, 2); + object obj0 = ObjectHelper.GetPropertyOrField(eo, pathElements[0]); + if(pathElements.Length > 1) { + HitSpans(new object[] { obj0 }, pathElements[1]); + } + } + } + + ignoresDataStore = didIgnoreStore; + } + //-------------------------------------------------------------------------------------- // IDataStore Impl --------------------------------------------------------------------- To unsubscribe from this list please visit: http://xircles.codehaus.org/manage_email |
|
|
Re: Performance problems: some more ideasDear list,
The main reason why we do a double work (once while fetching the rows and second evaluating the in-memory objects) is that we want to have an in-memory database. There are numerous advantages: we can cache results, we can use a disconnected scenario, we can create new objects or alter existing ones and without saving they are going to participate in the second stage of the query execution. The main problem with in-memory evaluation is that it doesn't implement indexing like the ordinary database. More precisely, it has only indexing for primary keys (which is buggy, btw). So, the spans problem could be solved if we implemented at least indexing for foreign keys. So, perhaps we could get involved with the project, or at least create a branch? Artem Tuesday, August 21, 2007, 6:28:23 PM, you wrote: > Dear list, > continuing on our earlier performance problems which we told you > about a month or two ago, we have implemented the "loop inversion" > for the spans that Artem proposed. The code is still a bit a proof > of concept and not up to good coding standards yet, but I've appended > the patches so you can have a look. Unfortunately, it shaved only a > few percent off the time spent on our queries with spans. > I'm now wondering why ObjectContext.GetObjects() first > loads the SQL query results into a DataSet, and then calls > FetchObjectsFromObjectTable() to again search within that > DataSet using a loop and EvaluateWithObject() -- something the > database server basically has already done for us. Our code spends > extraordinary amounts of time inside FetchObjectsFromObjectTable(). > I think it would make more sense to construct the result list > inside FetchObjectsFromStore() itself. It would need a little > extra administration, but I feel that that would easily outweigh > the time which is IMHO now wasted. > Is there any good reason why this is not done already? Maybe the call > to DbDataAdapter.Fill() inside DbDataStore.FillTable() somehow adds > unnecessary cruft into the DataTable that needs to be filtered out? > Or am I missing something else? > Any thoughts on this would be appreciated. > Gerben Vos, > ZyLAB Technologies. --------------------------------------------------------------------- To unsubscribe from this list please visit: http://xircles.codehaus.org/manage_email |
| Free embeddable forum powered by Nabble | Forum Help |