<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Jaros&#322;aw Zabie&#322;&#322;o - BLOG: Category Databases</title>
    <link>http://blog.zabiello.com/articles/category/databases</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>moje notatki, linki, komentarze</description>
    <item>
      <title>MySQLdb &amp;amp; client encoding</title>
      <description>&lt;p&gt;[vide: &lt;a href="http://blog.zabiello.com/pages/en/mysqldb-client-encoding"&gt;English version&lt;/a&gt;]&lt;/p&gt;


	&lt;p&gt;&lt;a href="http://sourceforge.net/projects/mysql-python"&gt;MySQLdb&lt;/a&gt; to g&#322;&#243;wna biblioteka dla Pythona obs&#322;uguj&#261;ca baz&#281; MySQL. Baza ta (od werseji 4.1 wzwy&#380;) ma wbudowany wygodny mechanizm translacji znak&#243;w jakie maj&#261; by&#263; wy&#347;wietlane dla klienta. Oczywi&#347;cie, nale&#380;y za&#322;o&#380;y&#263;, &#380;e natywnym formatem danych dla bazy to &lt;span class="caps"&gt;UTF&lt;/span&gt;-8. Za pomoc&#261; prostej kwerendy (SET &lt;span class="caps"&gt;NAMES&lt;/span&gt; latin2) mo&#380;na wymusi&#263; aby wszelkie napisy by&#322;y wypluwane do klienta w wybranym formacie (tu: iso-8859-2).&lt;/p&gt;


	&lt;p&gt;Ostatnio, przy okazji pracy z &lt;a href="http://pylonshq.com"&gt;Pylons&lt;/a&gt;, przyjrza&#322;em si&#281; bardzo ciekawemu projektowi: &lt;a href="http://www.sqlalchemy.org/"&gt;SQLAlchemy&lt;/a&gt;. Wszystko wskazuje na to, &#380;e &lt;a href="http://www.sqlobject.org/"&gt;SQLObject&lt;/a&gt; odejdzie do lamusa (tym bardziej &#380;e jego tw&#243;rca co&#347; go porzuci&#322; i planuje stworzy&#263; nowy SQLObject2). &lt;a href="http://www.sqlalchemy.org/"&gt;SQLAlchemy&lt;/a&gt; jest nie tylko znacznie pote&#380;niejszym &lt;a href="http://en.wikipedia.org/wiki/Object-relationship_modeling"&gt;&lt;span class="caps"&gt;ORM&lt;/span&gt;&lt;/a&gt;, ale ma tak&#380;e znacznie lepsz&#261; dokumentacj&#281; ni&#380; SQLObject &amp;#8211; ok. 117 stron samego tylko &lt;a href="http://www.sqlalchemy.org/docs/"&gt;manuala&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;Jedyny problem, jakie to typowe, to brak czytelnej opcji translacji polskich znak&#243;w. Podobny problem swego czasu znalaz&#322;em w Django (wys&#322;a&#322;em patcha i to poprawili dodaj&#261;c na sztywno &amp;#8220;SET &lt;span class="caps"&gt;NAMES&lt;/span&gt; utf8&amp;#8221;) W wypadku SQLAlchemy nie ma opcji do definicji kodowania po stronie klienta. Manual wspomina tylko o ustawieniu kodowania dla bazy, a to nie to samo. Okazuje, si&#281;, &#380;e rozwi&#261;zanie jest bardzo proste. Podczas tworzenia po&#322;&#261;czenia do bazy wystarczy u&#380;y&#263; dodatkowych parametr&#243;w. Nie ma potrzeby bawienia si&#281; w &#380;adne kwerendy &amp;#8220;SET &lt;span class="caps"&gt;NAMES&lt;/span&gt;&amp;#8221;. Owe parametry to &lt;strong&gt;use_unicode&lt;/strong&gt; i &lt;strong&gt;charset&lt;/strong&gt;:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="constant"&gt;MySQLdb&lt;/span&gt;
&lt;span class="ident"&gt;conn&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;MySQLdb&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;connect&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;
    &lt;span class="ident"&gt;user&lt;/span&gt;&lt;span class="punct"&gt;='&lt;/span&gt;&lt;span class="string"&gt;root&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; 
    &lt;span class="ident"&gt;passwd&lt;/span&gt;&lt;span class="punct"&gt;='&lt;/span&gt;&lt;span class="string"&gt;&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; 
    &lt;span class="ident"&gt;db&lt;/span&gt;&lt;span class="punct"&gt;='&lt;/span&gt;&lt;span class="string"&gt;test&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; 
    &lt;span class="ident"&gt;use_unicode&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="constant"&gt;False&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; 
    &lt;span class="ident"&gt;charset&lt;/span&gt;&lt;span class="punct"&gt;='&lt;/span&gt;&lt;span class="string"&gt;cp1250&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;W powy&#380;szym wypadku, MySQL b&#281;dzie zak&#322;ada&#322; &#380;e klient ma odebra&#263; teksty w formacie string&#243;w cp1250. Za&#347; w wypadku u&#380;ycia &amp;#8220;use_unicode=True&amp;#8221; zwracane b&#281;d&#261; &#347;liczne obiekty unicodowe! Przyk&#322;adowy plik konfiguracyjny dla Pylonsa korzystaj&#261;cego z SQLAlchemy (config/&lt;i&gt;init&lt;/i&gt;.py) mo&#380;e zatem wygl&#261;da&#263; np. tak:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;sqlalchemy&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="punct"&gt;*&lt;/span&gt;
&lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;sqlalchemy&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;pool&lt;/span&gt; &lt;span class="ident"&gt;as&lt;/span&gt; &lt;span class="ident"&gt;pool&lt;/span&gt;
&lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="constant"&gt;MySQLdb&lt;/span&gt;

&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;getconn&lt;/span&gt;&lt;span class="punct"&gt;():&lt;/span&gt;
    &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="constant"&gt;MySQLdb&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;connect&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;
        &lt;span class="ident"&gt;user&lt;/span&gt;&lt;span class="punct"&gt;='&lt;/span&gt;&lt;span class="string"&gt;root&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; 
        &lt;span class="ident"&gt;passwd&lt;/span&gt;&lt;span class="punct"&gt;='&lt;/span&gt;&lt;span class="string"&gt;&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; 
        &lt;span class="ident"&gt;db&lt;/span&gt;&lt;span class="punct"&gt;='&lt;/span&gt;&lt;span class="string"&gt;test&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; 
        &lt;span class="ident"&gt;use_unicode&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="constant"&gt;False&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; 
        &lt;span class="ident"&gt;charset&lt;/span&gt;&lt;span class="punct"&gt;='&lt;/span&gt;&lt;span class="string"&gt;utf8&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;

&lt;span class="ident"&gt;db&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;create_engine&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;
    &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;mysql://root:@localhost/test&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt;
    &lt;span class="ident"&gt;pool&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="ident"&gt;pool&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;QueuePool&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;getconn&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;pool_size&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="number"&gt;20&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;max_overflow&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="number"&gt;40&lt;/span&gt;&lt;span class="punct"&gt;),&lt;/span&gt; 
    &lt;span class="ident"&gt;strategy&lt;/span&gt;&lt;span class="punct"&gt;='&lt;/span&gt;&lt;span class="string"&gt;threadlocal&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;
&lt;span class="ident"&gt;metadata&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;BoundMetaData&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;db&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;

&lt;span class="ident"&gt;test_table&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Table&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;test&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="ident"&gt;metadata&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;autoload&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="constant"&gt;True&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;

&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Test(object):&lt;/span&gt;  
    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;__str__&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;):&lt;/span&gt;  
        &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;title&lt;/span&gt;  

&lt;span class="ident"&gt;test_mapper&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;mapper&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;Test&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;test_table&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;W powy&#380;szym przyk&#322;adzie, wymusi&#322;em kodowanie utf8 dla klienta oraz po&#322;&#261;czenie z baz&#261; dzia&#322;a&#263; b&#281;dzie w puli 20-40 w&#261;tk&#243;w. W&#322;a&#347;nie tego mi brakuje w Django: pracy wielow&#261;tkowej, bo zu&#380;ywa ona mniej pami&#281;ci. W/w model mo&#380;na u&#380;y&#263; w kontrolerze Pylons (controllers/home.py) np. tak:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;myproject&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;lib&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;base&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="punct"&gt;*&lt;/span&gt;
&lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;myproject&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;models&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="punct"&gt;*&lt;/span&gt;

&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;HomeController(BaseController):&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;index&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;):&lt;/span&gt;        
      &lt;span class="ident"&gt;c&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;rows&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;select&lt;/span&gt;&lt;span class="punct"&gt;([&lt;/span&gt;&lt;span class="ident"&gt;test_table&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;c&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;id&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;test_table&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;c&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;name&lt;/span&gt;&lt;span class="punct"&gt;]).&lt;/span&gt;&lt;span class="ident"&gt;execute&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;
      &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="ident"&gt;render_response&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;/home.myt&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <pubDate>Wed, 16 Aug 2006 01:28:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:a7940b1d-4893-4e0a-b1aa-60d91a5a1207</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2006/08/16/mysqldb-client-encoding</link>
      <category>Databases</category>
      <category>Pylons</category>
      <category>Python</category>
      <category>mysql</category>
      <category>pylons</category>
      <category>python</category>
      <category>sqlalchemy</category>
    </item>
    <item>
      <title>MySQL5 - rehabilitacja</title>
      <description>&lt;p&gt;Po paru godzinach test&#243;w i walki z bazami MySQL 5.0.21 i PostgreSQL 8.1.4, musz&#281; zwr&#243;ci&#263; troch&#281; honoru bazie MySQL. PostgreSQL to bardzo zaawansowana i pot&#281;&#380;na baza danych, jednak&#380;e, jak &lt;a href="http://blog.zabiello.com/articles/2006/05/29/postgresql-inne-problemy"&gt;pisa&#322;em wcze&#347;niej&lt;/a&gt;, ma jeden, zasadniczy feler, kt&#243;ry j&#261; wyklucza z moich zastosowa&#324; &amp;#8211; kiepsk&#261; obs&#322;ug&#281; r&#243;&#380;nych kodowa&#324; w ramach jednej bazy danych. Pr&#243;ba napisania aplikacji wieloj&#281;zycznej sortuj&#261;cej i wyszukuj&#261;cej z uwzgl&#281;dnianiem wielu r&#243;&#380;nych j&#281;zyk&#243;w jest bardzo trudna. Praktycznie nie ma sensu aby do tego u&#380;y&#263; PostgreSQL.&lt;/p&gt;


	&lt;p&gt;Tutaj pokazuje swoje mo&#380;liwo&#347;ci MySQL 5. na razie nie mam potwierdzonych informacji o s&#322;abej stabilno&#347;ci tak jak to by&#322;o z &lt;a href="http://blog.zabiello.com/articles/2006/05/29/mysql-5-strze%C5%BC-si%C4%99-si%C4%99-tego-koszmaru"&gt;wersjami wcze&#347;niejszymi&lt;/a&gt;. Za&#347; problem dziwacznego zachowania si&#281; warunku &lt;span class="caps"&gt;LIKE&lt;/span&gt;&amp;#8230; ot&#243;&#380; uda&#322;o mi si&#281; za pomoc&#261; pr&#243;b i b&#322;&#281;d&#243;w po&#322;&#261;czonych z przeszukiwaniem dokumentacji, ustali&#263; ostateczne rozwi&#261;zanie.&lt;/p&gt;


	&lt;p&gt;Po kolei. Wpierw trzeba wiedzie&#263;, &#380;e MySQL 5 (cho&#263; jest to ju&#380; od wersji 4.1) udost&#281;pni&#322; obs&#322;ug&#281; wieloj&#281;zyczno&#347;ci na znacznie lepszym poziomie ni&#380; inne bazy. Ot&#243;&#380; mo&#380;na &#322;atwo zdefiniowa&#263; niezale&#380;ne traktowanie tekstu dla ka&#380;dej tabeli w ramach tej samej bazy. Ma&#322;o tego, mo&#380;na p&#243;j&#347;&#263; dalej i zdefiniowa&#263; niezale&#380;ne kodowanie dla ka&#380;dego pola tekstowego oddzielnie.&lt;/p&gt;


	&lt;p&gt;Daje to niebywa&#322;&#261; elastyczno&#347;&#263; i komfort w obs&#322;udze tekst&#243;w mi&#281;dzynarodowych. Mo&#380;na bowiem wymusi&#263; aby w tekstach polskich dzia&#322;a&#322;o sortowanie zgodne z zasadami j&#281;zyka polskiego oraz aby du&#380;e i ma&#322;e polskie ogonki by&#322;y traktowane tak samo przy wyszukiwaniu. Inne pole mo&#380;e posiada&#263; identyczne regu&#322;y dla j&#281;zyka niemieckiego, szwedzkiego, itp. itd. Jedynym za&#322;o&#380;eniem jest aby kodowanie takich tabel i/lub p&#243;l by&#322;o w &lt;span class="caps"&gt;UTF8&lt;/span&gt;. To jest wewn&#281;trzny format w jakim trzeba trzyma&#263; dane tekstowe. Nie ma on nic wsp&#243;lnego z kodowaniem jakie uzyskuje klient. Odpada w og&#243;le konieczno&#347;&#263; pisania w&#322;asnych procedur aby to przekodowywa&#263;. Ca&#322;a robot&#281; za nas  &amp;#8220;odwali&amp;#8221; MySQL. Chcesz w swoich skryptach wypluwa&#263; do przegl&#261;darki polskie ogonki w formacie &lt;span class="caps"&gt;ISO&lt;/span&gt;-8859-2? &#379;aden problem. Wywo&#322;aj kwerend&#281; &amp;#8220;SET &lt;span class="caps"&gt;NAMES&lt;/span&gt; latin2&amp;#8221; i potem wykonuj &lt;span class="caps"&gt;SELECT&lt;/span&gt;&amp;#8230;&lt;/p&gt;


Samo kodowanie znak&#243;w to dopiero pocz&#261;tek. Chcemy tak&#380;e aby dzia&#322;a&#322;o sortowanie i wyszukiwanie bez wra&#380;liwo&#347;ci na wielko&#347;&#263; liter. Aby to dzia&#322;a&#322;o nale&#380;y zadba&#263; o to aby ka&#380;de pole posiada&#322;o  odpowiedni&#261; definicj&#281; tzw. collation. Dla j&#281;zyka polskiego b&#281;dzie to utf8_polish_ci. Przyk&#322;adowa definicja tabeli (z dodatkowymi bajerami jakie daje MySQL, np. kompresj&#281; indeks&#243;w) mog&#322;aby wygl&#261;da&#263; np. tak:
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_sql "&gt;CREATE TABLE `artykul` (
  `id` int(11) NOT NULL auto_increment,
  `tytul` varchar(255) collate utf8_polish_ci NOT NULL,
  `tresc` text collate utf8_polish_ci NOT NULL,
  PRIMARY KEY  (`id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_polish_ci PACK_KEYS=1 CHECKSUM=1 DELAY_KEY_WRITE=1 ROW_FORMAT=COMPRESSED;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;MySQL &lt;a href="http://dev.mysql.com/doc/refman/5.0/en/charset-collate.html"&gt;udostepnia tak&#380;e s&#322;owo &lt;span class="caps"&gt;COLLATE&lt;/span&gt;&lt;/a&gt; do bardzo wygodnej obs&#322;ugi tekst&#243;w mi&#281;dzynarodowych. Lista dost&#281;pnych j&#281;zyk&#243;w jest podana &lt;a href="http://dev.mysql.com/doc/refman/5.0/en/charset.html"&gt;w dokumentacji&lt;/a&gt; i jest imponuj&#261;ca.&lt;/p&gt;


	&lt;p&gt;Gdzie le&#380;a&#322; zatem problem z &lt;a href="http://blog.zabiello.com/articles/2006/05/29/mysql-5-strze%C5%BC-si%C4%99-si%C4%99-tego-koszmaru"&gt;dziwnym zachowaniem&lt;/a&gt; si&#281; bazy? Po prostu nie by&#322;o zdefinowanego &#380;adnego collation i baza troch&#281; zwariowa&#322;a. Na pewno by&#322;oby lepiej, aby w takiej sytuacji zachowywa&#322;a si&#281; bardziej przewidywalnie. Ale wystarczy&#322;o dodanie definicji odpowiedniego zestawu j&#281;zyka i wszystko wr&#243;ci&#322;o do normy.&lt;/p&gt;</description>
      <pubDate>Tue, 30 May 2006 14:04:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:0a6e0ded-f63e-47da-a5d8-0a6e63f2e2e8</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2006/05/30/mysql5-rehabilitacja</link>
      <category>Databases</category>
    </item>
    <item>
      <title>PostgreSQL - inne problemy</title>
      <description>&lt;p&gt;Zauwa&#380;y&#322;em, &#380;e problem z dziwacznym dzia&#322;aniem kwerend MySQL5 korzystaj&#261;cych z &lt;span class="caps"&gt;LIKE&lt;/span&gt; nie wyst&#281;puje pod Linuksem. By&#263; mo&#380;e to po  prostu przypad&#322;o&#347;&#263; kiepsko przygotowanej binarki dla Windows&#243;w&amp;#8230;&lt;/p&gt;


	&lt;p&gt;Najbardziej bolesna sprawa zwi&#261;zana z &lt;a href="http://postgresql.org"&gt;PostgreSQL&lt;/a&gt; (dalej: PG) jest z&#322;a implementacja wersji mi&#281;dzynarodowych. Tzn. PG ustawia jedn&#261; collations &lt;strong&gt;dla ca&#322;ej bazy&lt;/strong&gt; co skutecznie uniemo&#380;liwia to, aby w ramach jednej bazy u&#380;ywa&#263; r&#243;&#380;nych tabel z r&#243;&#380;nymi sortowaniami (wg r&#243;&#380;nych j&#281;zyk&#243;w).&lt;/p&gt;


	&lt;p&gt;Za&#347; MySQL potrafi ustawi&#263; niezale&#380;nie collation nawet dla poszczeg&#243;lnych kolumn!&lt;/p&gt;


	&lt;p&gt;Pr&#243;bowa&#322;em przeszuka&#263; listy dyskusyjne na temat PG, ale &lt;a href="http://groups.google.com/group/pgsql.general/browse_thread/thread/c34ca786a3b63973/d89346af9ea2293d?q=collation&amp;#38;rnum=7#d89346af9ea2293d"&gt;to, co znalaz&#322;em&lt;/a&gt;, potwierdza moje obawy: PG ma to &#378;le zrobione. Je&#347;li chc&#281; mie&#263; efekt sortowania  i takiego samego traktowania du&#380;ych i ma&#322;ych znak&#243;w (istotne przy wi&#281;kszo&#347;ci wyszukiwa&#324; tekstu) to musia&#322;bym dla ka&#380;dego j&#281;zyka tworzy&#263; oddzieln&#261; baz&#281;. To raczej nie wchodzi w gr&#281;.&lt;/p&gt;</description>
      <pubDate>Mon, 29 May 2006 21:00:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:64c71b24-72a1-4923-ba7c-a094ff376a63</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2006/05/29/postgresql-inne-problemy</link>
      <category>Databases</category>
      <category>postgresql</category>
    </item>
    <item>
      <title>MySQL 5 - strze&#380; si&#281; si&#281; tego koszmaru</title>
      <description>&lt;p&gt;Baza MySQL nigdy nie uchodzi&#322;a za wz&#243;r poprawnej pracy, ale to co ostatnio si&#281; z ni&#261; dzieje wo&#322;a o pomst&#281; do nieba&amp;#8230; Zainstalowa&#322;em sobie najnowsz&#261; wersj&#281; stabiln&#261; MySQL 5 pod win32. Wpierw mysla&#322;em &#380;e znalaz&#322;em jaki&#347; b&#322;&#261;d we frameworku &lt;a href="http://djangoproject.com"&gt;Django&lt;/a&gt;. Ale kr&#243;tki czat z innymi programistami i &lt;a href="http://forums.mysql.com/read.php?103,84263,89870"&gt;przejrzenie netu&lt;/a&gt;, pozbawi&#322; mnie z&#322;udze&#324;. &lt;strong&gt;B&#322;&#261;d le&#380;y w silniku samej bazy&lt;/strong&gt;. W&#322;&#261;czy&#322;em logowanie zapyta&#324; i uruchomi&#322;em kwerend&#281; bezpo&#347;rednio z poziomu klienta.&lt;/p&gt;


	&lt;p&gt;Ot&#243;&#380; okazuje si&#281;, &#380;e w MySQL5 kompletnie popsuta jest obs&#322;uga warunku &amp;#8220;LIKE&amp;#8221;. Ilo&#347;&#263; zwracanych rekord&#243;w jest &lt;strong&gt;wi&#281;ksza ni&#380; by&#263; powinna&lt;/strong&gt;. I to nie chyba ma nic wsp&#243;lnego z tym, czy kodowanie tabel jest w &lt;span class="caps"&gt;UTF8&lt;/span&gt; czy nie, gdy&#380; nadmierna ilo&#347;&#263; rekord&#243;w jest znajdowana nawet, jak wyszukuje si&#281; s&#322;owo zawiera tylko znaki &lt;span class="caps"&gt;ASCII&lt;/span&gt;.&lt;/p&gt;


	&lt;p&gt;Inne &amp;#8220;kwiatki&amp;#8221; zwi&#261;zane z MySQL, o kt&#243;rych trzeba sobie jasno powiedzie&#263;, to notoryczne niszczenie plik&#243;w indeksowych w wypadku zbyt du&#380;ego obci&#261;&#380;enia bazy. Oczywi&#347;cie to mo&#380;na &#322;atwo naprawi&#263; za pomoc&#261; kwerendy &lt;span class="caps"&gt;REPAIR TABLE&lt;/span&gt; tabelka. Ale dop&#243;ki nie wykona si&#281; tej operacja, tabela &lt;strong&gt;nie jest dost&#281;pna&lt;/strong&gt; i aplikacja nam si&#281; wywali. Tego typu problemy zauwa&#380;y&#322;em  na MySQL 4.x i 4.1. Nie mia&#322;em okazji podda&#263; wi&#281;kszym obci&#261;&#380;eniom baz&#281; MySQL 5.x, ale nie zdziwi&#322;bym si&#281; jakby te&#380; z ni&#261; by&#322;y problemy.&lt;/p&gt;


	&lt;p&gt;Zawsze tyle si&#281; m&#243;wi w bran&#380;y, &#380;e MySQL to niepowa&#380;ny projekt amatorski (s&#322;aba stabilno&#347;&#263; i niszczenie swoich tabel pod du&#380;ym obci&#261;&#380;eniem, koszmarnie wolne tabele transakcyjne innodb, s&#322;aba obs&#322;uga lockowania &amp;#8211; tylko na poziomie tabel a nie wierszy itp, itd)   Niszczenie swoich tabel indeksowych mog&#322;em jeszcze zdzier&#380;y&#263;, ale b&#322;&#281;dna obs&#322;uga wyszukiwania tak podstawowej operacji jak &lt;span class="caps"&gt;LIKE&lt;/span&gt;? No way. Ca&#322;e szcz&#281;&#347;cie, &#380;e Django ma dobry &lt;span class="caps"&gt;ORM&lt;/span&gt; i mo&#380;na &#322;atwo zmigrowa&#263; do PostgreSQL. Chyba nie ma innego wyboru jak powiedzie&#263;: &amp;#8220;Goodbye MySQL and welcome PostgreSQL!&amp;#8221;&lt;/p&gt;


	&lt;p&gt;Zobacz c.d. &lt;a href="http://blog.zabiello.com/articles/2006/05/30/mysql5-rehabilitacja"&gt;MySQL5 rehabilitacja&lt;/a&gt;&lt;/p&gt;</description>
      <pubDate>Mon, 29 May 2006 09:54:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:829ef093-eaa3-4878-a24f-9dd6a2cab70d</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2006/05/29/mysql-5-strze%C5%BC-si%C4%99-si%C4%99-tego-koszmaru</link>
      <category>Databases</category>
      <category>mysql</category>
    </item>
  </channel>
</rss>
