Re: The wisdom of the object mentors (Was: Searching OO Associations with RDBMS Persistence Models)
Date: 29 Jun 2006 01:19:22 -0700
Robert Martin wrote:
> On 2006-06-20 11:36:46 -0700, "Marshall" <marshall.spight_at_gmail.com> said:
> > Robert Martin wrote:
> >> On 2006-06-13 13:22:40 -0400, "Marshall" <marshall.spight_at_gmail.com> said:
> >>> Can you state what the benefit of lazy loading is?
> >> Yes. There are two that I can think of on the spur of the moment.
> >> 1. We don't pay for what we don't use. i.e. if some very late decision
> >> means that we don't need the data, we don't have to fetch it.
> > This is also an attribute of simple querying. Don't need the data?
> > Don't query it. Lazy loading doesn't help this at all. This is a
> > non-problem.
> You asked me for the benefits of lazy loading. You did not ask me to
> compare lazy loading with queries. Indeed, I cannot do the latter
> since the two are orthogonal. I can implement lazy loading with
Let me be more explicit then.
Consider a dbms-using application that is in a position to benefit from "we don't pay for what we don't use." This would necessarily be because it was querying for some information that it wasn't using at the time.
Two approaches to dealing with this probem spring to mind:
- Use a QueryCache manager, and refactor our code that does queries to do the queries through the cache manager. The cache manager could be hardwired for specific queries, parameterized by externally-defined queries, or, most impressively, support a custom query language with the full expressiveness of SQL. Calls in to the query cache manager would build and execute SQL to identify the rows of the table(s) that we are interested in, and return proxy objects that contain just enough information to be able to identify the specific remote row that is being proxied. When getter methods on the proxy are invoked, the proxy object issues a query to fill in just the field the getter is associated with. Subsequent calls to the getter will not issue any queries; although the data will be immediately stale and subject to race conditions on update, this cost will be offset by the fact that you now have a cache manager with per-row, perattribute resolution.
2) Fix the query so it doesn't return unneeded data.
Approach 1 (aka lazy loading) can be seen to dramatically increase the number of queries issued, increase code size and complexity, increase latency, and reduce data freshness BUT reduce memory usage compared to the original state.
Approach 2, querying what you need when you need it, reduces memory usage compared to the original state.
PS. Thought experiment continuing item 1, category 3 (custom query language with SQL expressivity):
You now have a powerful framework in which you pass strings to the QueryCacheManager to execute, and much useful work happens under the covers. Now, generify it. Instead of returning code-generated proxies, build a single, reflective class capable of handling the results of *all* queries. It should support reflective calls to tell you what columns are in the result, and have methods for iterating through the rows, thus avoiding any overhead of object creation/ destruction. Now release to SourceForge and bask in the glory that comes to authors of O/R mapping frameworks.
Conclusion of thought experiment: note that the framework described corresponds to JDBC.
QueryCacheManager = java.sql.Connection
custom query language = SQL
method you invoke passing a string in query language = java.sql.Statement.execute(String)
generified return data container = java.sql.ResultSet Received on Thu Jun 29 2006 - 10:19:22 CEST