~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/lp/app/doc/batch-navigation.txt

  • Committer: Launchpad Patch Queue Manager
  • Date: 2011-07-12 01:56:30 UTC
  • mfrom: (13404.1.1 revert-13392)
  • Revision ID: launchpad@pqm.canonical.com-20110712015630-mzy3uu3ujp5pqi9e
[release-critical=wgrant][r=wgrant][rollback=13392] Revert r13392. It
 breaks when there are multiple batchnavs on a single page.

Show diffs side-by-side

added added

removed removed

Lines of Context:
47
47
  ...     'Cupid', 'Donner', 'Blitzen', 'Rudolph']
48
48
 
49
49
 
 
50
Performance with SQLObject
 
51
==========================
 
52
 
 
53
This section demonstrates that batching generates sensible SQL queries when
 
54
used with SQLObject, i.e. that it puts appropriate LIMIT clauses on queries.
 
55
 
 
56
Imports and initialization:
 
57
 
 
58
  >>> from lp.testing.pgsql import CursorWrapper
 
59
  >>> from canonical.launchpad.database.emailaddress import EmailAddress
 
60
  >>> from canonical.launchpad.interfaces.lpstorm import IStore
 
61
  >>> ignore = IStore(EmailAddress) # Prime the database connection.
 
62
  ... # (Priming is important if this test is run in isolation).
 
63
  >>> CursorWrapper.record_sql = True
 
64
 
 
65
Prepare a query, and create a batch of the results:
 
66
 
 
67
  >>> select_results = EmailAddress.select(orderBy='id')
 
68
  >>> batch_nav = BatchNavigator(select_results, build_request(), size=10)
 
69
  >>> email_batch = batch_nav.currentBatch()
 
70
  >>> batch_items = list(email_batch)
 
71
 
 
72
Because we're only looking at the first batch, the database is only
 
73
asked for the first 11 rows. (lazr.batchnavigator asks for 11 instead
 
74
of 10 so that it can reliably detect the end of the dataset).
 
75
 
 
76
  >>> len(CursorWrapper.last_executed_sql)
 
77
  1
 
78
  >>> print CursorWrapper.last_executed_sql[0]
 
79
  SELECT ... FROM EmailAddress ... LIMIT 11...
 
80
 
 
81
Get the next 10.  The database is only asked for the next 11 rows:
 
82
 
 
83
  >>> CursorWrapper.last_executed_sql = []
 
84
  >>> email_batch2 = email_batch.nextBatch()
 
85
  >>> batch_items = list(email_batch2)
 
86
  >>> len(CursorWrapper.last_executed_sql)
 
87
  1
 
88
  >>> CursorWrapper.last_executed_sql[0].endswith('LIMIT 11 OFFSET 10')
 
89
  True
 
90
 
 
91
As seen above, simply accessing the batch doesn't trigger a SQL query
 
92
asking for the length of the entire resultset. But explicitly asking
 
93
for the length will trigger a SQL query in most circumstances.
 
94
 
 
95
  >>> CursorWrapper.last_executed_sql = []
 
96
  >>> ignored = email_batch.total()
 
97
  >>> print CursorWrapper.last_executed_sql[0]
 
98
  SELECT COUNT(*) FROM EmailAddress
 
99
 
 
100
There are exceptions. When the current batch is the last one in the
 
101
list, it's possible to get the length of the entire resultset without
 
102
triggering a COUNT query.
 
103
 
 
104
  >>> CursorWrapper.last_executed_sql = []
 
105
  >>> batch_nav = BatchNavigator(select_results, build_request(), size=50)
 
106
  >>> final_batch = batch_nav.currentBatch().nextBatch()
 
107
  >>> batch_items = list(final_batch)
 
108
  >>> ignored = final_batch.total()
 
109
  >>> print "\n".join(CursorWrapper.last_executed_sql)
 
110
  SELECT ... FROM EmailAddress ... OFFSET 0
 
111
  SELECT ... FROM EmailAddress ... OFFSET 50
 
112
 
 
113
When the current batch contains the entire resultset, it's possible to
 
114
get the length of the resultset without triggering a COUNT query.
 
115
 
 
116
  >>> CursorWrapper.last_executed_sql = []
 
117
  >>> one_page_nav = BatchNavigator(select_results, build_request(), size=200)
 
118
  >>> only_batch = one_page_nav.currentBatch()
 
119
  >>> batch_items = list(only_batch)
 
120
  >>> ignored = only_batch.total()
 
121
  >>> print "\n".join(CursorWrapper.last_executed_sql)
 
122
  SELECT ... FROM EmailAddress ... OFFSET 0
 
123
 
50
124
Multiple pages
51
125
==============
52
126
 
53
127
The batch navigator tells us whether multiple pages will be used.
54
128
 
55
 
    >>> from canonical.launchpad.database.emailaddress import EmailAddress
56
 
    >>> select_results = EmailAddress.select(orderBy='id')
57
 
    >>> batch_nav = BatchNavigator(select_results, build_request(), size=50)
58
129
    >>> batch_nav.has_multiple_pages
59
130
    True
60
131
 
61
 
    >>> one_page_nav = BatchNavigator(select_results, build_request(), size=200)
62
132
    >>> one_page_nav.has_multiple_pages
63
133
    False
64
134