It makes sense that getCount() on the cursor might involve reading all
the rows even if it probably doesn't actually instantiate all the
objects as Bob Kerns correctly points out.

A work around is to do a seperate "select count(*)" with the same
where clause but this is only an estimate of the number of rows the
cursor will return since possibly rows can be inserted or deleted
between selecting the count and selecting the cursor.  You can also do
"select count(*), column1, column2..." so you get the count on every
row.  Finding the current relative "page" is another challenge...



On Feb 3, 8:23 pm, Bob Kerns <[email protected]> wrote:
> Ah, the difference between theory and practice is that in theory,
> there IS no difference, but in practice, there IS.
>
> What platform did you do this on?
>
> I was afraidgetCount() was going to turn out to be slow. But I'm
> puzzled that it's slow, but SELECT COUNT(*) FROM <TABLE> is relatively
> quick. Clearly, the database is capable of better behavior.
>
> It's pretty typical for reverse cursor motion to be more expensive,
> but this is rather larger than I'd have expected.
>
> The discontinuity at 12000 rows, in each direction, makes me suspect
> it's using a max window size of 12,000, which is nuts on a phone, and
> really wants to be configurable.
>
> I'm also wondering if CursorWindow.freeLastRow() is ever being called
> -- and if not, what would happen if we were to call it at suitable
> points.
>
> You didn't indicate whether you are using PreparedStatements -- if
> not, some of the overhead may come from parsing and managing the
> queries. Or, given a weak implementation -- it might not matter
> anyway.
>
> I wonder if we could supply our own CursorWindow subclass that behaves
> better? The documentation is rather lacking...
>
> Another factor to consider here is the database's caching. If you use
> LIMIT to only query a small portion, you could make a derived cursor
> that (excluding transaction differences) behaves more reasonably in
> terms of how much it fetches. But then you'll be executing changing
> queries over and over, so you may be doing more work on the back end.
> Given the memory constraints, I suspect each subsequent query will
> cost about the same as the first...
>
> Maybe, to be scientific about this, I should write my own tests, we
> compare notes, trade programs, and get a bunch of people to try them
> on different platforms. I might have time if I don't answer any
> questions for a while... :=)!
>
> This is an important use case; it's worth understanding well. I wonder
> if anyone has already covered this ground?
>
> On Feb 3, 1:47 pm, THill <[email protected]> wrote:
>
> > What you say makes sense Bob, but testing seems to indicate the
> > Android SQLite implementation isn't so proper.
>
> > I have a simple app that creates 20001 rows in a table, each with an
> > int _id & 2 varchar fields.
>
> > Getting the count of rows via db.rawQuery("select count(*) from
> > table", null) and getting the value from the resulting cursor takes
> > 0.2s.
>
> > Getting the count of rows using
> >     cursor=db.rawQuery("select _id, field1, field2 from table",
> > null);  //NOTE: no 'where' or 'order by'
> >     count=cursor.getCount()
> > takes 4.5s.
>
> > During this time, the log has messages:
> >     E/CursorWindow(  695): need to grow: mSize = 1048576, size = 29,
> > freeSpace() = 19, numRows = 11832
> >     E/CursorWindow(  695): not growing since there are already 11832
> > row(s), max size 1048576
> >     E/Cursor  (  695): Failed allocating 29 bytes for text/blob at
> > 11831,1
> >     D/Cursor  (  695): finish_program_and_get_row_count row 8169
>
> > So,getCount() is certainly not optimal, and appears to be allocating
> > something based on result set size.  The list view requests the count
> > of items up front, so a slowgetCount() can impact the UI if you just
> > trust SimpleCursorAdapter on large, simple queries.
>
> > When scrolling down the list, each bindView results in a
> > cursor.moveToPosition() call.  Doing this in a test app shows that
> > moving to 1000, 2000, ..., 20000 each takes 1ms -- except when going
> > from 11000 to 12000, which takes >2s.  No additional log messages.
>
> > Where it gets u.g.l.y. is when moving from position 20000 backward to
> > 0.  20000, ..., 12000 take 1ms, but moving from 12000 to 11000,
> > 10000, ..., 0 *each* take 4.5s (!).  This is really fun to observe
> > when scrolling backward in the list from 12000.  Once you hit some
> > point, every row takes 4.5s before it is shown.
>
> > When this starts happening, every move results in log messages like:
> >     D/dalvikvm(  320): GC freed 251 objects / 13256 bytes in 116ms
> >     E/CursorWindow(  763): need to grow: mSize = 1048576, size = 29,
> > freeSpace() = 21, numRows = 11631
> >     E/CursorWindow(  763): not growing since there are already 11631
> > row(s), max size 1048576
> >     E/Cursor  (  763): Failed allocating 29 bytes for text/blob at
> > 19630,1
> >     D/Cursor  (  763): finish_program_and_get_row_count row 370
>
> > This would again indicate the cursor is not agnostic to the result set
> > size.  I'll be doing more testing with many smaller query cursors
> > behind a single adapter, but there appears to be a clear threshold.

-- 
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en

Reply via email to