pátek 29. července 2005

JTDS driver – pozor na nastavení pro MSSQL 2000

JTDS driver je v podstatě skoro jediný nekomerční driver použitelný pro MSSQL 7.0 a 2000. Právě jeho původní určení pro MSSQL 7.0 pravděpodobně zanechalo pozůstatek v defaultním nastavení driveru, které může na MSSQL 2000 způsobit vážné výkonnostní problémy. Celá blamáž se točí kolem převodu textových parametrů na UNICODE. Objasnění problému a řešení se objevilo i na naší firemní WIKI a já jej zde se svolením autora republikuji.

JTDS driver a převod textových parametrů na UNICODE

Autor: Budík (special thanks to NkD & Tuhoslav)

Driver JTDS v sobě má implementovaný parametr sendStringParametersAsUnicode, který se stará o převod parametrů posílaných v SQL příkazech na server do typu UNICODE. Defaultní nastavení tohoto parametrů je true, což znamená, že převod je prováděn. I když je to jistě velmi zajímavá možnost, může být příčinou velkých problémů.

MSSQL 7.0 na rozdíl od MSSQL 2000 má nastavenu jednu znakovou sadu pro celou databázi. MSSQL 2000 umožňuje nastavit znakovou sadu na každý sloupec. Následně se může stát to, co byla příčina obrovských problémů v produkčním nasazení. Při provdádění selektu z tabulky DCH_WW, která čítá 2 500 000 záznamů, existovala v selektu tato podmínka (po dosazení parametru):

...AND OSCIS = ' xyz'

do databáze však doteče toto:

...AND OSCIS = N' xyz'

Ono N znamená převod řetezce na UNICODE. Potíž nastavá v okamžiku, kdy si uvědomíte, že sloupec je typu CHAR a parametr UNICODE. Nedojde totiž k aplikaci nastavených db indexů a provádí se procházení celé tabulky. V aplikaci bylo navíc zvoleno řešení, kdy se daný selekt musel udělat v rámci jednoho požadavku vícekrát, aby se mohly získat patřičná data.

Řešení je problému poměrně jednoduché - definovat v JTDS driveru hodnotu parametru sendStringParametersAsUnicode na hodnotu false. Pokud se tak udělá a restartuje se AS, dojde k tomu, že do databáze už dojde selekt bez převodu na UNICODE, automaticky se aplikuje index (což bylo v tomto případě nenajevýš žádoucí) a rázem jeden selekt, který předtím v nejlepším případě běžel 5 sekund, běží 80 milisekund.

Drobná poznámka - pokud si myslíte, že to N je už součástí aplikačního logu, tak se mýlíte. To N se objeví při v detailním monitorování pomocí SQL Profileru.

Nakonec citace z dokumentace k JTDS driveru:

sendStringParametersAsUnicode (default - true)

sendStringParametersAsUnicode (default - true) Determines whether string parameters are sent to the SQL Server database in Unicode or in the default character encoding of the database. This seriously affects SQL Server 2000 performance since it does not automatically cast the types (as 7.0 does), meaning that if a index column is Unicode and the string is submitted using the default character encoding (or the other way around) SQLServer will perform an index scan instead of an index seek.