Reading the docs for arraysize, its not clear if this only applies to
fetchone() and a non-arg fetchmany(), or to all fetches (I'm hoping
you have better detail on this.). If the former, why not call
fetchmany() or fetchall() ? The ORM uses fetchall()/fetchmany() when
receiving rows. If the latter, that seems pretty strange that
cx_oracle would still make 100 individual calls for a fetchmany(100)
when just one would do.
this is the same as the document which I read on the cx_oracle website.
What happens if I say:
cursor.fetchall()
?
does it make one "round trip" per row ? or do a full fetch in one
"round trip" ? similar question for fetchmany(n).
>
> I am glad to see the fix is on the way. This is the only thing that's
> holding me back using SQLAlchemy. By the way, can we also ensure that
> we will be able to change this parameter more easily? Thanks
I dont think changing this parameter is the solution. Just call
fetchall() or fetchmany(). I think calling fetchone() should fetch
only one row, IMHO.
sorry to hassle you on this but it would be of great help if you could
create a small test case using cx_oracle only, which inserts around
10,000 rows into a table and then uses various methods, like
fetchmany() with and without the manual "arraysize" setting, to get
them back. You can time each function using Timeit or alternatively
just using time.time(). If cx_oracle is in fact optimizing
fetchmany() for *only* the case that no argument is passed, which
would be amazingly weird, we can add an engine-level setting for this
easily enough but I need confirmation that this is the case.
> Quote:
>
> Up to this point the default arraysize is 1 meaning that a single row
> is internally fetched at a time. This has nothing to do with
> fetchone(), fetchmany() or fetchall(). Regardless of which of those
> methods is used, internally cx_Oracle fetches one row at a time. If
> you change the arraysize to 50, internally cx_Oracle will fetch 50
> rows at a time. Again, this is regardless of whether you use
> fetchone(), fetchmany() or fetchall(). Some of the confusion may lie
> in the fact that the default value for rows to fetch in fetchmany() is
> the arraysize -- but that is all it is, a default value!
see, that's a really unfortunate decision on his part to reuse
"arraysize" in such an arbitrary way like that, while *not* using it
at the point at which it is entirely reasonable, that is when you have
already stated you want to fetchmany(n) or fetchall(). This is
totally a bug in cx_oracle.
>
> class MyConnection(cx_Oracle.Connection):
>
> def cursor(self):
> cursor = cx_Oracle.Cursor(self)
> cursor.arraysize = 50
> return cursor
>
> What this does is automatically set the arraysize to 50 every time a
> cursor is created. This can be done to transparently set the arraysize
> and should allow you to proceed with whatever code needs to assume an
> arraysize of that value. Otherwise you can feel free to change it
> yourself after creating the cursor.
>
> And as has already been noted, in the next release of cx_Oracle, the
> default arraysize will be 50 in order to resolve this problem
> "permanently". :-)
that workaround works, and also implementing "default_arraysize"
within OracleDialect as follows is acceptable. If someone can test
this and post a trac ticket I can commit this to 0.4/0.5:
Index: lib/sqlalchemy/databases/oracle.py
===================================================================
--- lib/sqlalchemy/databases/oracle.py (revision 4819)
+++ lib/sqlalchemy/databases/oracle.py (working copy)
@@ -213,6 +213,12 @@
self.out_parameters[name] =
self.cursor.var(dbtype)
self.parameters[0][name] =
self.out_parameters[name]
+ def create_cursor(self):
+ cursor = self._connection.connection.cursor()
+ if self.dialect.default_arraysize:
+ cursor.arraysize = self.dialect.default_arraysize
+ return cursor
+
def get_result_proxy(self):
if hasattr(self, 'out_parameters'):
if self.compiled_parameters is not None and
len(self.compiled_parameters) == 1:
@@ -242,8 +248,9 @@
supports_pk_autoincrement = False
default_paramstyle = 'named'
- def __init__(self, use_ansi=True, auto_setinputsizes=True,
auto_convert_lobs=True, threaded=True, allow_twophase=True, **kwargs):
+ def __init__(self, use_ansi=True, auto_setinputsizes=True,
auto_convert_lobs=True, threaded=True, allow_twophase=True,
default_arraysize=None, **kwargs):
default.DefaultDialect.__init__(self, **kwargs)
+ self.default_arraysize = default_arraysize
self.use_ansi = use_ansi
self.threaded = threaded
self.allow_twophase = allow_twophase
On May 27, 2008, at 5:34 PM, gniquil wrote: