Le jeudi 25 octobre 2012 17:28:37 UTC+2, Michael Bayer a écrit : > > the "convert_unicode=Force" flag does this. documentation at > http://docs.sqlalchemy.org/en/rel_0_7/core/types.html?highlight=unicode#sqlalchemy.types.String.__init__. >
Hi Michael, Did you read my original message ? It was about the unability to use this flag at engine configuration level. > > > > > On Oct 25, 2012, at 10:48 AM, David Moore wrote: > > Hi Yann, > > Sorry for the confusion - my email was musing about what I thought > sqlalchemy should do, not what I thought you should do. > > The way we have solved this is using the cx_Oracle inputtypehandler hook. > So we've overriden where the connection is created by sqlalchemy, and then > used the following snippet: > > def OracleInputTypeHandler(cursor, value, numElements): > if isinstance(value, unicode): > return cursor.var(str, arraysize = numElements, > inconverter = lambda x: > x.encode(cursor.connection.nencoding)) > > connection.inputtypehandler = OracleInputTypeHandler > > This converts all unicode bind parameters passed into cx_Oracle into the > client encoding. > > HTH, > Dave Moore > > ------------------------------ > > Le jeudi 25 octobre 2012 16:21:49 UTC+2, David Moore a écrit : >> >> Hello, >> > > Hi, > >> >> In line with what is required for Python 3, would it not make sense to >> insist across the board that bind values to sqlalchemy.String should be >> bytestrings and that bind values to sqlalchemy.Unicode should be unicode >> strings, converting if necessary? >> > > I am using the Unicode class and not String directly. But the code I was > referring to is in the String class. > > >> I don't think I understand why you would not want that ever. >> > > I am using unicode strings, but I'd like sqlalchemy to convert them to the > dialect encoding in order to avoid a problem with oracle indexes not being > used when querying with unicode strings. > > >> >> regards, >> Dave Moore >> >> ------------------------------ >> >> Hi, >> >> Having had the same problem as above, I would like to use the >> "convert_unicode='force'" flag at engine configuration level. >> It seems that String tests the value of "convert_unicode" at its own >> level as well as engine level, but it isn't the case for the 'force' value >> check : >> >> def bind_processor(self, dialect): >> if self.convert_unicode or dialect.convert_unicode: >> if dialect.supports_unicode_binds and \ >> *self.convert_unicode != 'force'*: >> ... >> >> def result_processor(self, dialect, coltype): >> wants_unicode = self.convert_unicode or dialect.convert_unicode >> needs_convert = wants_unicode and \ >> (dialect.returns_unicode_strings is not True or >> *self.convert_unicode == 'force'*) >> >> Thus I have to create a type decorator for all my Strings even if I have >> set the right flag at engine configuration level... >> >> Yann >> >> >> Le jeudi 2 août 2012 23:22:22 UTC+2, Michael Bayer a écrit : >>> >>> so the "convert_unicode='force'" flag is not ideal here as that will >>> spend most of it's time checking for decodes necessary on the result set >>> side, which is a lot of wasted effort. You can customize how strings are >>> handled on the bind side, including per-dialect behavior, using a custom >>> type: >>> >>> class MyStringType(TypeDecorator): >>> impl = String >>> >>> def process_bind_param(self, value, dialect): >>> if value is not None and dialect.name == "oracle": >>> value = value.encode('utf-8') >>> >>> then replace usage of the String(length=XYZ) type with >>> MyStringType(length=XYZ). >>> >>> docs: >>> http://docs.sqlalchemy.org/en/rel_0_7/core/types.html#types-custom >>> >>> >>> On Aug 2, 2012, at 5:41 AM, David Moore wrote: >>> >>> > Hi, >>> > >>> > Further searching seems to indicate this is an Oracle issue, not a >>> cx_Oracle issue. >>> > http://www.digipedia.pl/usenet/thread/15912/2814/ - same problem with >>> cx_Oracle >>> > http://support.unify.com/supportforum/viewtopic.php?f=40&t=3823 - >>> happening with perl drivers. >>> > http://tao.qshine.com/note/note_ora.htm - happening with ADO.NET >>> drivers. >>> > >>> > There's also evidence this problem occurs with MS SQL Server as well: >>> > >>> http://www.microsoftfaqs.com/Articles/1148439/Index_not_used_when_UNICODE_%3D_true >>> - SQL Server 2005 >>> > >>> http://blog.brianhartsock.com/2008/12/14/nvarchar-vs-varchar-in-sql-server-beware/ >>> >>> > >>> > Although, it seems in SQL Server at least, it still uses the index, >>> just in a slower manner, which is probably why we haven't noticed this >>> issue yet. >>> > >>> > It seems to me that the place to fix this is when the type of the >>> column is known, which is when sqlalchemy binds the parameter. There's >>> some discussion in one of those links that, at the sql statement >>> preparation level, you don't know what the column datatype is, so you can't >>> fix it there. >>> > >>> > Would it be possible for String datatypes to detect unicode values and >>> encode them with the database charset? >>> > >>> > As a lower-level temporary solution, you can get cx_Oracle to encode >>> all unicode parameters to strings, but that's obviously the wrong thing to >>> do if you have any Unicode columns. This snippet: >>> > >>> > def InputTypeHandler(cursor, value, numElements): >>> > if isinstance(value, unicode): >>> > return cursor.var(str, arraysize = numElements, >>> > inconverter = lambda x: >>> x.encode(cursor.connection.nencoding)) >>> > >>> > And then when creating the connection: >>> > >>> > connection.inputtypehandler = InputTypeHandler >>> > >>> > thanks for the help, >>> > >>> > -- >>> > David Moore >>> > Senior Software Engineer >>> > St. James Software >>> > Email: dav...@sjsoft.com >>> > >>> > >>> > ----- Original Message ----- >>> >> And for anyone else experiencing this issue, there was a subtle >>> >> difference in the execution plans that's now apparent. The >>> >> statement which only selects colid runs a FAST FULL SCAN and >>> >> successfully converts the unicode parameter using SYS_OP_C2C, and >>> >> uses the index. When you select both colid and message, it runs a >>> >> FULL SCAN, and even though it seems to detect the conversion can be >>> >> done, it does not use the index at all. Perhaps this is actually an >>> >> Oracle issue? >>> >> >>> >> -- >>> >> David Moore >>> >> Senior Software Engineer >>> >> St. James Software >>> >> Email: dav...@sjsoft.com >>> >> >>> >> >>> >> >>> >> ----- Original Message ----- >>> >>> Hi Michael, >>> >>> >>> >>> Indeed, you are correct - adding the message column to the >>> >>> cx_oracle >>> >>> query shows the same behaviour as the sqlalchemy query. Sorry I >>> >>> missed that. >>> >>> >>> >>> I will take these results to the cx_oracle list on this basis. On >>> >>> my >>> >>> second question, though, is there a way to enforce >>> >>> convert_unicode='force' only on Oracle databases across an >>> >>> application? I know the hooking syntax changed from sqlalchemy 0.6 >>> >>> to 0.7, so I'd imagine if there is a way, it would be different for >>> >>> those two versions. >>> >>> >>> >>> thanks, >>> >>> >>> >>> -- >>> >>> David Moore >>> >>> Senior Software Engineer >>> >>> St. James Software >>> >>> Email: dav...@sjsoft.com >>> >>> >>> >>> >>> >>> ----- Original Message ----- >>> >>>> Hi David - >>> >>>> >>> >>>> I've done some experiments with the script you gave me. Correct >>> >>>> me >>> >>>> if I'm wrong (which is very possible), but the attached revised >>> >>>> version appears to demonstrate the difference between the >>> >>>> cx_oracle >>> >>>> and SQLAlchemy versions is really just that the SQLAlchemy >>> >>>> version >>> >>>> is running a different SQL string: >>> >>>> >>> >>>> SELECT test_table.colid, test_table.message >>> >>>> FROM test_table >>> >>>> WHERE test_table.colid = :colid_1 >>> >>>> >>> >>>> whereas the cx_oracle version, critically, does not ask for the >>> >>>> "message" column: >>> >>>> >>> >>>> SELECT test_table.colid FROM test_table WHERE >>> test_table.colid = >>> >>>> :colid >>> >>>> >>> >>>> it's not clear to me if the placement of the "message" column >>> >>>> impacts >>> >>>> the Oracle planner, or otherwise if the latency is on the >>> >>>> cx_oracle >>> >>>> side regarding buffering of columns or something similar. But >>> >>>> i >>> >>>> am able to get the SQLAlchemy version to be as fast as the >>> >>>> cx_oracle >>> >>>> version, and the cx_oracle version to be as slow as the >>> >>>> sqlalchemy >>> >>>> version, by just adding/removing the "message" column from the >>> >>>> query. >>> >>>> >>> >>>> The attached script also tries to eliminate the overhead of >>> >>>> SQLAlchemy compiling the SQL construct within the timed portion, >>> >>>> as >>> >>>> I was testing this against only 40K rows and wanted to try to get >>> >>>> the results as close as possible. It's only dealing with the >>> >>>> unicode parameter, and it's true if you encode the parameter >>> >>>> first, >>> >>>> both the SQLA and cx_oracle versions get faster, even to the >>> >>>> point >>> >>>> that the two-column version minus unicode is faster than the one >>> >>>> column version with unicode. My guess is that cx_oracle is >>> >>>> detecting a unicode value in the input and doing something >>> >>>> different >>> >>>> with the statement overall as a result of it being present. >>> >>>> >>> >>>> Some typical set of results are: >>> >>>> >>> >>>> Setting up table >>> >>>> sa_both_cols 1.20209717751 >>> >>>> sa_one_col 0.0182020664215 >>> >>>> sa_literal_sql 0.019690990448 >>> >>>> cx_oracle_one_col 0.0839619636536 >>> >>>> cx_oracle_both_cols 1.18438816071 >>> >>>> >>> >>>> Setting up table >>> >>>> sa_both_cols 1.17753505707 >>> >>>> sa_one_col 0.0785720348358 >>> >>>> sa_literal_sql 0.016618013382 >>> >>>> cx_oracle_one_col 0.0194280147552 >>> >>>> cx_oracle_both_cols 1.15302705765 >>> >>>> >>> >>>> while the cx_oracle/SQLA versions seem to compete for the "fast" >>> >>>> version, which is because we're only running the statement once >>> >>>> and >>> >>>> I'm running on a low performing amazon small instance, it's clear >>> >>>> the "two column" version is where the vast amount of latency >>> >>>> occurs >>> >>>> for both systems. >>> >>>> >>> >>>> >>> >>>> let me know if you can confirm similar results on your end. I >>> >>>> tested >>> >>>> only with SQLAlchemy 0.8 in trunk but I was able to reproduce >>> >>>> your >>> >>>> initial results so I assume the experience with 0.7, 0.6 would be >>> >>>> similar. >>> >>>> >>> >>>> >>> >>>> >>> >>>> >>> >>>> >>> >>>> >>> >>>> >>> >>>> >>> >>>> >>> >>>> On Aug 1, 2012, at 6:40 AM, David Moore wrote: >>> >>>> >>> >>>>> Hi all, >>> >>>>> >>> >>>>> This is a bug in a product with multiple versions in support. >>> >>>>> The >>> >>>>> issue can be reproduced with >>> >>>>> sqlalchemy: 0.6.1, 0.6.6, 0.7.8 >>> >>>>> cx_Oracle: 5.0.4, 5.1, 5.1.2 >>> >>>>> Oracle: 10g XE and 10g Enterprise >>> >>>>> >>> >>>>> We have tables created with sqlalchemy.String primary keys and >>> >>>>> other indexes. When querying through sqlalchemy, when we pass >>> >>>>> in >>> >>>>> a unicode value for the key, Oracle does not use the index, and >>> >>>>> instead uses a full table scan. When executing the exact same >>> >>>>> query through cx_Oracle, we don't see this issue. The script >>> >>>>> attached is a small test case which demonstrates the issue. >>> >>>>> Sample output: >>> >>>>> >>> >>>>> Running select >>> >>>>> Unicode params took 3.455 seconds >>> >>>>> Encoded params took 0 seconds >>> >>>>> Running cx_Oracle select >>> >>>>> Unicode params took 0.0619998 seconds >>> >>>>> Encoded params took 0 seconds >>> >>>>> >>> >>>>> And running the cx_Oracle select first to prevent pollution by >>> >>>>> caching: >>> >>>>> >>> >>>>> Running cx_Oracle select >>> >>>>> Unicode params took 0.0469999 seconds >>> >>>>> Encoded params took 0 seconds >>> >>>>> Running select >>> >>>>> Unicode params took 3.267 seconds >>> >>>>> Encoded params took 0.0159998 seconds >>> >>>>> >>> >>>>> As can be seen, there's a slight slowdown with the unicode >>> >>>>> parameter on cx_Oracle, but nothing compared to the slowdown on >>> >>>>> sqlalchemy. The sqlalchemy unicode parameter select is the >>> >>>>> only >>> >>>>> one which performs a full table scan, so that makes sense. >>> >>>>> >>> >>>>> This issue has been mentioned on this list before - 15 Feb with >>> >>>>> title "Full Table scan with Oracle due to Charset conversion" >>> >>>>> and >>> >>>>> 4 April with title "Problem with Oracle requests" - but in >>> >>>>> those >>> >>>>> cases, the issue was reproducible with the cx_Oracle driver as >>> >>>>> well, which it is not here. >>> >>>>> >>> >>>>> Using the convert_unicode='force' argument to the String types >>> >>>>> does >>> >>>>> solve the issue, but there are a few reasons I don't want to do >>> >>>>> that. This product also supports PostgreSQL, SQL Server and >>> >>>>> MySQL, and I do not want to make changes which will affect >>> >>>>> running >>> >>>>> under those databases. This is also happening in an otherwise >>> >>>>> very stable product under long-term support in a number of >>> >>>>> places, >>> >>>>> so whatever change is made needs to be minimal. >>> >>>>> >>> >>>>> Adding an additional function-based index on SYS_OP_C2C(column) >>> >>>>> for >>> >>>>> each of the affected columns also solves this issue with a >>> >>>>> slight >>> >>>>> performance change for the extra indexes which need to be kept >>> >>>>> up >>> >>>>> to date. This is the stopgap solution we've gone for in the >>> >>>>> meantime for those systems on production. It's not ideal, >>> >>>>> though, >>> >>>>> and a bit difficult to automate and then verify the results. >>> >>>>> We'd >>> >>>>> prefer to know why this was happening, and maybe fix a >>> >>>>> sqlalchemy >>> >>>>> issue in the process. >>> >>>>> >>> >>>>> So, my questions are: >>> >>>>> * What is sqlalchemy doing differently to straight cx_Oracle >>> >>>>> that >>> >>>>> triggers this behaviour? How can I debug this further to find >>> >>>>> out? >>> >>>>> * Is there a way, on sqlalchemy 0.6.x, to set up a hook which >>> >>>>> will >>> >>>>> use convert_unicode='force' only on an Oracle database and >>> >>>>> only >>> >>>>> for String columns, automatically across an application? >>> >>>>> There's >>> >>>>> no create_engine argument for convert_unicode='force', which >>> >>>>> is >>> >>>>> a >>> >>>>> pity. >>> >>>>> * And a hook for sqlalchemy 0.7.x to achieve the same result? >>> >>>>> >>> >>>>> Thanks in advance for any help, >>> >>>>> regards, >>> >>>>> -- >>> >>>>> David Moore >>> >>>>> Senior Software Engineer >>> >>>>> St. James Software >>> >>>>> Email: dav...@sjsoft.com >>> >>>>> >>> >>>>> -- >>> >>>>> You received this message because you are subscribed to the >>> >>>>> Google >>> >>>>> Groups "sqlalchemy" group. >>> >>>>> To post to this group, send email to >>> >>>>> sqlal...@googlegroups.com. >>> >>>>> To unsubscribe from this group, send email to >>> >>>>> sqlalchemy+...@googlegroups.com. >>> >>>>> For more options, visit this group at >>> >>>>> http://groups.google.com/group/sqlalchemy?hl=en. >>> >>>>> >>> >>>>> <oracle_sqlalchemy_encoding_error.py> >>> >>>> >>> >>>> >>> >>>> -- >>> >>>> You received this message because you are subscribed to the >>> >>>> Google >>> >>>> Groups "sqlalchemy" group. >>> >>>> To post to this group, send email to sqlal...@googlegroups.com. >>> >>>> To unsubscribe from this group, send email to >>> >>>> sqlalchemy+...@googlegroups.com. >>> >>>> For more options, visit this group at >>> >>>> http://groups.google.com/group/sqlalchemy?hl=en. >>> >>>> >>> >>>> >>> >>> >>> >>> -- >>> >>> You received this message because you are subscribed to the Google >>> >>> Groups "sqlalchemy" group. >>> >>> To post to this group, send email to sqlal...@googlegroups.com. >>> >>> To unsubscribe from this group, send email to >>> >>> sqlalchemy+...@googlegroups.com. >>> >>> For more options, visit this group at >>> >>> http://groups.google.com/group/sqlalchemy?hl=en. >>> >>> >>> >>> >>> >> >>> >> -- >>> >> You received this message because you are subscribed to the Google >>> >> Groups "sqlalchemy" group. >>> >> To post to this group, send email to sqlal...@googlegroups.com. >>> >> To unsubscribe from this group, send email to >>> >> sqlalchemy+...@googlegroups.com. >>> >> For more options, visit this group at >>> >> http://groups.google.com/group/sqlalchemy?hl=en. >>> >> >>> >> >>> > >>> > -- >>> > You received this message because you are subscribed to the Google >>> Groups "sqlalchemy" group. >>> > To post to this group, send email to sqlal...@googlegroups.com. >>> > To unsubscribe from this group, send email to >>> sqlalchemy+...@googlegroups.com. >>> > For more options, visit this group at >>> http://groups.google.com/group/sqlalchemy?hl=en. >>> > >>> >>> -- >> You received this message because you are subscribed to the Google Groups >> "sqlalchemy" group. >> To view this discussion on the web visit >> https://groups.google.com/d/msg/sqlalchemy/-/xQHoRrrfOugJ. >> To post to this group, send email to sqlal...@googlegroups.com. >> To unsubscribe from this group, send email to >> sqlalchemy+...@googlegroups.com. >> For more options, visit this group at >> http://groups.google.com/group/sqlalchemy?hl=en. >> >> >> >> >> -- >> David Moore >> Senior Software Engineer >> St. James Software >> Email: dav...@sjsoft.com >> >> > > > -- > David Moore > Senior Software Engineer > St. James Software > Email: dav...@sjsoft.com <javascript:> > > -- > You received this message because you are subscribed to the Google Groups > "sqlalchemy" group. > To post to this group, send email to sqlal...@googlegroups.com<javascript:> > . > To unsubscribe from this group, send email to > sqlalchemy+...@googlegroups.com <javascript:>. > For more options, visit this group at > http://groups.google.com/group/sqlalchemy?hl=en. > > > -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To view this discussion on the web visit https://groups.google.com/d/msg/sqlalchemy/-/bAGLNKapvSMJ. To post to this group, send email to sqlalchemy@googlegroups.com. To unsubscribe from this group, send email to sqlalchemy+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.