<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>guzik &#187; MySQL</title>
	<atom:link href="http://guzik.net.pl/blog/category/tech/db/mysql-tech/feed/" rel="self" type="application/rss+xml" />
	<link>http://guzik.net.pl/blog</link>
	<description>Mój blog</description>
	<lastBuildDate>Wed, 28 Jul 2010 20:35:46 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>FortiAnalyzer i MySQL</title>
		<link>http://guzik.net.pl/blog/2010/04/fortianalyzer-i-mysql/</link>
		<comments>http://guzik.net.pl/blog/2010/04/fortianalyzer-i-mysql/#comments</comments>
		<pubDate>Fri, 09 Apr 2010 20:51:52 +0000</pubDate>
		<dc:creator>guzik</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[FortiAnalyzer]]></category>
		<category><![CDATA[Fortinet]]></category>

		<guid isPermaLink="false">http://guzik.net.pl/blog/?p=1769</guid>
		<description><![CDATA[W dokumencie FortiAnalyzer v4.0 MR2 Release Notes w rozdziale &#8217;1.1 Summary of Enhancements Provided by FortiAnalyzer v4.0 MR2 Release&#8217; można znaleźć między innymi coś takiego: Remote SQL database (MySQL) support SQL DB PostgreSQL support Przyznam, że zaintrygowało mnie to na tyle, że postanowiłem od razu sprawdzić z czym to się je i co można z tego [...]]]></description>
			<content:encoded><![CDATA[<p>W dokumencie <a title="ftp://support.fortinet.com/FortiAnalyzer/v4.00/4.0MR2/MR2/FortiAnalyzer-v4.0-MR2-Release-Notes.pdf" href="ftp://support.fortinet.com/FortiAnalyzer/v4.00/4.0MR2/MR2/FortiAnalyzer-v4.0-MR2-Release-Notes.pdf">FortiAnalyzer v4.0 MR2 Release Notes</a> w rozdziale &#8217;1.1 Summary of Enhancements Provided by FortiAnalyzer v4.0 MR2 Release&#8217; można znaleźć między innymi coś takiego:</p>
<ul>
<li>Remote SQL database (MySQL) support</li>
<li>SQL DB PostgreSQL support</li>
</ul>
<p>Przyznam, że zaintrygowało mnie to na tyle, że postanowiłem od razu sprawdzić z czym to się je i co można z tego wycisnąć.<br />
<span id="more-1769"></span><br />
Konfiguracja prosta &#8211; jak na załączonym obrazku:</p>
<p><a href="http://guzik.net.pl/blog/wp-content/uploads/2010/04/famysql.jpg"><img class="aligncenter size-medium wp-image-1770" title="famysql" src="http://guzik.net.pl/blog/wp-content/uploads/2010/04/famysql-300x133.jpg" alt="" width="300" height="133" /></a><br />
Podajemy sposób przechowywania danych (<em>Location</em>): lokalny to prawdopodobnie PostgreSQL i zdalny, czyli MySQL. Wybrałem ten ostatni. Po uzupełnieniu niezbędnych danych (serwer, użytkownik, hasło, baza) zaznaczyłem logowanie wszystkich typów zdarzeń.<br />
Jeśli użytkownik, którego podamy ma prawo do zakładania baz, nic więcej nie musimy robić. W przeciwnym razie należy mu pomóc.<br />
Poniżej kawałek mojego <em>query log</em>&#8216;a:</p>
<blockquote><p><code>Connect fa@A.B.C.D on<br />
Query create database if not exists `fortianalyzer`<br />
Query use `fortianalyzer`<br />
Query select tbl_name from table_ref where tbl_name like 'FG100A3907510579-elog-%' and row_num=0<br />
</code></p></blockquote>
<p>Czyli mamy połączenie z serwerem, próbę założenia oraz podłączenie do bazy, a następnie przeszukanie tabeli <code>table_ref</code> (założona wcześniej). Tabela ta zawiera informacje o innych tablicach z logami &#8211; podejrzewam, że zaplanowana została jakaś rotacja (wskazują na to kolumny <code>itime_start</code>, <code>itime_end</code>, <code>dtime_start</code>, <code>dtime_end</code>, <code>row_num</code>). Czemu tylko podejrzewam, a nie wiem? Otóż w przypadku, gdy nie zostanie znaleziony żaden wynik, FortiAnalyzer próbuje stworzyć nową tablicę. U mnie próbuje, bo nikt nie pomyslał, że baza może mieć domyślne kodowanie ustawione na <code>utf8</code> zamiast np. <code>latin1</code>, a przy ograniczeniach MySQL nie każdą tablicę da się założyć. Jakiej się nie da? Wyczerpująco opisuje to dodatek <a title="http://dev.mysql.com/doc/refman/5.1/en/column-count-limit.html" href="http://dev.mysql.com/doc/refman/5.1/en/column-count-limit.html">D.7.2. The Maximum Number of Columns Per Table</a> dokumentacji MySQL.<br />
Zapytanie jak poniżej:</p>
<blockquote><p><code>create table `FG100A3907510579-elog-20100409220517` (`id` bigint unsigned not null primary key,`itime` datetime,`dtime` datetime,`cluster_id` varchar(24),`device_id` varchar(16),`log_id` smallint unsigned default 0,`subtype` varchar(255),`type` varchar(255),`timestamp` int unsigned default 0,`pri` varchar(255),`vd` varchar(255),`user` varchar(255),`msg` varchar(255),`ssid` varchar(255),`action` varchar(255),`session_id` int unsigned default 0,`count` int unsigned default 0,`proto` varchar(255),`profile` varchar(255),`cpu` tinyint unsigned default 0,`src` varchar(40),`epoch` int unsigned default 0,`mem` tinyint unsigned default 0,`duration` int unsigned default 0,`infected` int unsigned default 0,`from` varchar(255),`dst` varchar(40),`ha_group` tinyint unsigned default 0,`tunnel_id` int unsigned default 0,`status` varchar(255),`bssid` varchar(255),`tunnel_type` varchar(255),`event_id` int unsigned default 0,`ip` varchar(40),`ha_role` varchar(255),`rem_ip` varchar(40),`src_int` varchar(255),`suspicious` int unsigned default 0,`sn` varchar(255),`to` varchar(255),`total_session` int unsigned default 0,`ap` varchar(255),`scanned` int unsigned default 0,`vcluster` int unsigned default 0,`remote_ip` varchar(40),`carrier_ep` varchar(255),`imsi` varchar(255),`loc_ip` varchar(40),`dst_int` varchar(255),`from_vcluster` int unsigned default 0,`rem_port` smallint unsigned default 0,`src_port` smallint unsigned default 0,`msisdn` varchar(255),`tunnel_ip` varchar(40),`intercepted` int unsigned default 0,`vap` varchar(255),`service` varchar(255),`apn` varchar(255),`out_intf` varchar(255),`blocked` int unsigned default 0,`dst_port` smallint unsigned default 0,`mac` varchar(255),`to_vcluster` int unsigned default 0,`acct_stat` varchar(255),`selection` varchar(255),`reason` varchar(255),`group` varchar(255),`rate` tinyint unsigned default 0,`loc_port` smallint unsigned default 0,`vcluster_member` int unsigned default 0,`vcluster_state` varchar(255),`app-type` varchar(255),`nsapi` tinyint unsigned default 0,`dport` smallint unsigned default 0,`channel` tinyint unsigned default 0,`cookies` varchar(255),`checksum` int unsigned default 0,`dst_host` varchar(255),`nf_type` varchar(255),`vdname` varchar(255),`linked-nsapi` tinyint unsigned default 0,`next_stats` int unsigned default 0,`virus` varchar(255),`imei-sv` varchar(255),`devintfname` varchar(255),`security` varchar(255),`policy_id` int unsigned default 0,`rai` varchar(255),`hostname` varchar(255),`xauth_user` varchar(255),`uli` varchar(255),`xauth_group` varchar(255),`sent` bigint unsigned default 0,`policyid` int unsigned default 0,`rcvd` bigint unsigned default 0,`sess_duration` int unsigned default 0,`hbdn_reason` varchar(255),`banned_src` varchar(255),`end-usr-address` varchar(40),`msg-type` tinyint unsigned default 0,`sync_type` varchar(255),`banned_rule` varchar(255),`state` varchar(255),`vpn_tunnel` varchar(255),`sync_status` varchar(255),`alert` varchar(255),`sensor` varchar(255),`endpoint` varchar(255),`stage` tinyint unsigned default 0,`voip_proto` varchar(255),`deny_cause` varchar(255),`desc` varchar(255),`dir` varchar(255),`kind` varchar(255),`init` varchar(255),`mode` varchar(255),`cert-type` varchar(255),`ui` varchar(255),`exch` varchar(255),`rat-type` varchar(255),`c-gsn` varchar(40),`error_num` varchar(255),`u-gsn` varchar(40),`method` varchar(255),`phase2_name` varchar(255),`spi` varchar(255),`name` varchar(255),`c-sgsn` varchar(40),`request_name` varchar(255),`seq` varchar(255),`c-ggsn` varchar(40),`in_spi` varchar(255),`u-sgsn` varchar(40),`out_spi` varchar(255),`u-ggsn` varchar(40),`c-sgsn-teid` int unsigned default 0,`enc_spi` varchar(255),`c-ggsn-teid` int unsigned default 0,`dec_spi` varchar(255),`message_type` varchar(255),`malform_desc` varchar(255),`tunnel` varchar(255),`u-sgsn-teid` int unsigned default 0,`u-ggsn-teid` int unsigned default 0,`malform_data` int unsigned default 0,`tunnel-idx` int unsigned default 0,`line` varchar(255),`column` int unsigned default 0,`c-pkts` bigint unsigned default 0,`phone` varchar(255),`profile_group` varchar(255),`c-bytes` bigint unsigned default 0,`u-pkts` bigint unsigned default 0,`u-bytes` bigint unsigned default 0,`next_stat` int unsigned default 0,`user_data` varchar(255),`role` varchar(255),`result` varchar(255),`xauth_result` varchar(255),`esp_transform` varchar(255),`esp_auth` varchar(255),`error_reason` varchar(255),`peer_notif` varchar(255))</code></p></blockquote>
<p>zakończy się niepowodzeniem, a serwer zwróci błąd:</p>
<blockquote><p><code>ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. You have to change some columns to TEXT or BLOBs</code></p></blockquote>
<p>Nie chce mi się nawet liczyć ile bajtów to zajmuje. A wystarczyło dopisać <code>CHARACTER SET latin1</code>&#8230;</p>
<p>Podejrzewam, że po poprawnym założeniu tabeli dopisze się coś do <code>table_ref</code>, ale jest już zbyt późno, a ja mam za dużo lat, żeby dochodzić jak to powinno wyglądać.</p>
<p>Tak czy inaczej &#8211; inżynierowie Fortinet tracą jeden punkt.</p>
]]></content:encoded>
			<wfw:commentRss>http://guzik.net.pl/blog/2010/04/fortianalyzer-i-mysql/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MySQL: konwersja daty i import plików &#8211; studium przypadku</title>
		<link>http://guzik.net.pl/blog/2010/01/mysql-konwersja-daty-i-import-plikow-studium-przypadku/</link>
		<comments>http://guzik.net.pl/blog/2010/01/mysql-konwersja-daty-i-import-plikow-studium-przypadku/#comments</comments>
		<pubDate>Wed, 13 Jan 2010 14:07:28 +0000</pubDate>
		<dc:creator>guzik</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[OTC]]></category>
		<category><![CDATA[OTC Terminal]]></category>

		<guid isPermaLink="false">http://guzik.net.pl/blog/?p=1495</guid>
		<description><![CDATA[Niniejszy wpis powstał przy rozwiązywaniu konkretnego problemu. Jest tu opis polecenia LOAD DATA INFILE (import danych z pliku) oraz sposób wykonania konwersji daty podczas importu danych, co może komuś się przydać (niekoniecznie przy walce z takim samym problemem). Opis problemu: Potrzebujemy wyciągnąć wszystkie próby logowania z wykorzystaniem programu OTC Terminal konkretnego dnia, albo o konkretnej [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft" title="MySQL logo" src="http://www.mysql.com/common/logos/sakila.png" alt="" width="121" height="79" />Niniejszy wpis powstał przy rozwiązywaniu konkretnego problemu. Jest tu opis polecenia <a title="http://dev.mysql.com/doc/refman/5.1/en/load-data.html" href="http://dev.mysql.com/doc/refman/5.1/en/load-data.html">LOAD DATA INFILE</a> (import danych z pliku) oraz sposób wykonania konwersji daty podczas importu danych, co może komuś się przydać (niekoniecznie przy walce z takim samym problemem).<br />
<span id="more-1495"></span><br />
<strong>Opis problemu</strong>: Potrzebujemy wyciągnąć wszystkie próby logowania z wykorzystaniem programu <a title="http://www.otc.pl/index.asp?s=84&amp;l=1" href="http://www.otc.pl/index.asp?s=84&amp;l=1">OTC Terminal</a> konkretnego dnia, albo o konkretnej godzinie każdego dnia zdefiniowanego użytkownika.</p>
<p><strong>Rozeznanie terenu</strong>: Wspomniany program tworzy log w następującym formacie:</p>
<blockquote><p><code> 4. BS2          LOGIN ERROR   25.03.2009 07:02:08  Password expired.<br />
4. BS2          CHPWD OK      25.03.2009 07:02:16  Password for user 'BS2' successfully changed.<br />
0. BS2          LOGIN OK      30.03.2009 06:54:25<br />
1. BS2          LOGIN OK      30.03.2009 06:54:29<br />
0. BS2          LOGOUT OK     30.03.2009 06:54:29<br />
1. BS2          LOGOUT OK     30.03.2009 06:54:42<br />
10. BS2          LOGOUT ERROR  24.04.2009 11:47:58  Login limit (session)<br />
6. BS2          LOGIN ERROR   21.05.2009 14:32:57  No such name<br />
</code></p></blockquote>
<p>Nie wnikam co oznacza pierwsza kolumna w logach, kolejne to: nazwa użytkownika, akcja, data oraz godzina, a także dodatkowa informacja dla akcji. Nie interesuje nas zarówno pierwsza, jak i ostatnia kolumna. Plik tekstowy ma kolumny o stałej szerokości (tutaj tego nie widać).<br />
Do realizacji zadania można użyć <a title="http://www.gnu.org/software/gawk/" href="http://www.gnu.org/software/gawk/">awk</a>, <a title="http://sed.sourceforge.net/" href="http://sed.sourceforge.net/">sed</a>, <a title="http://www.gnu.org/software/grep/" href="http://www.gnu.org/software/grep/">grep</a>, <a title="http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/find.mspx?mfr=true" href="http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/find.mspx?mfr=true">find</a> (Windows) lub innych podobnych narzędzi w połączeniu z wyrażeniami regularnymi, ale można też skorzystać z bazy danych, która będzie przechowywać wspomniane informacje w konkretnym formacie, a samo przeszukiwanie będzie wygodniejsze, szybsze i bardziej elastyczne.</p>
<p><strong>Realizacja</strong>: Za pomocą arkusza kalkulacyjnego przekształciłem logi w format CSV (najszybsze, co przyszło mi do głowy). Wyrzuciłem niepotrzebne kolumny. Utworzyłem tabelę w MySQL, która może wciągnąć te dane:</p>
<blockquote><p><code>CREATE TABLE `trmlog` (<br />
`user` char(3) NOT NULL,<br />
`action` varchar(24) DEFAULT NULL,<br />
`date` date DEFAULT NULL,<br />
`time` time DEFAULT NULL,<br />
KEY `useridx` (`user`),<br />
KEY `dateidx` (`date`)<br />
) ENGINE=InnoDB DEFAULT CHARSET=utf8</code></p></blockquote>
<p>Data i godzina są osobno. Jako, że data ma postać DD.MM.YYYY, a chcemy YYYY-MM-DD, stworzyłem funkcję, która może to skonwertować (nie wiem czy MySQL w locie coś może sam zrobić):</p>
<blockquote><p><code>delimiter //</code></p>
<p><code><a title="http://dev.mysql.com/doc/refman/5.0/en/create-procedure.html" href="http://dev.mysql.com/doc/refman/5.0/en/create-procedure.html">CREATE FUNCTION</a> dateconv (date CHAR(10)) RETURNS DATE<br />
BEGIN<br />
RETURN CONCAT(<a title="http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_substring" href="http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_substring">SUBSTRING</a>(date, 7), "-", SUBSTRING(date, 4, 2), "-", SUBSTRING(date, 1, 2));<br />
END//</code></p>
<p><code>delimiter ;</code></p></blockquote>
<p>I ostatecznie zaimportowałem dane:</p>
<blockquote><p><code>LOAD DATA INFILE 'E:\\temp\\termlog\\log.csv' INTO TABLE trmlog FIELDS TERMINATED BY ';' (user, action, @var1, time) SET date = dateconv(@var1);</code></p></blockquote>
<p>Uwagi wymaga proces konwersji kolumny z datą. Domyślnie LOAD DATA INFILE zakłada, że każde pole w pliku CSV odpowiada jednej kolumnie w tabeli. Jeśli chcemy zaimportować dane tylko do niektórych kolumn, musimy podać ich nazwy (czy sam ich porządek). Jeśli natomiast chcemy je w jakiś sposób przekształcić, używamy klauzuli <code>SET</code>, która może przybrać różne formy. Po przykłady odsyłam do <a title="http://dev.mysql.com/doc/refman/5.1/en/" href="http://dev.mysql.com/doc/refman/5.1/en/">dokumentacji MySQL</a>. U mnie wygląda to tak, że do kolumny <code>date</code> wciągamy dane, które wyrzuci nam (nasza własna) funkcja <code>dateconv()</code>. Może nie do końca intuicyjne, ale nie tak trudne.<br />
Dalej obrabiamy to jak chcemy w SQL.</p>
<p>Oczywiście nie musimy używać MySQL, a jeśli już użyliśmy, zawsze możemy migrować do innej bazy:</p>
<li><a title="http://www.heise-online.pl/newsticker/news/item/Microsoft-chce-pomoc-w-migracji-z-MySQL-a-na-SQL-Server-902665.html" href="http://www.heise-online.pl/newsticker/news/item/Microsoft-chce-pomoc-w-migracji-z-MySQL-a-na-SQL-Server-902665.html">Microsoft chce pomóc w migracji z MySQL-a na SQL Server</a></li>
]]></content:encoded>
			<wfw:commentRss>http://guzik.net.pl/blog/2010/01/mysql-konwersja-daty-i-import-plikow-studium-przypadku/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Trochę Lua w mysql-proxy</title>
		<link>http://guzik.net.pl/blog/2009/11/troche-lua-w-mysql-proxy/</link>
		<comments>http://guzik.net.pl/blog/2009/11/troche-lua-w-mysql-proxy/#comments</comments>
		<pubDate>Mon, 02 Nov 2009 12:31:38 +0000</pubDate>
		<dc:creator>guzik</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[LUA]]></category>
		<category><![CDATA[mysql-proxy]]></category>

		<guid isPermaLink="false">http://guzik.net.pl/blog/?p=1181</guid>
		<description><![CDATA[Replikacja baz MySQL działa jako tako. Jeśli to typ MASTER &#8211; SLAVE, to na ogół ten drugi serwer się nudzi. Skoro się nudzi, można wykorzystać go do zapytań, które nie zmieniają niczego (SELECT). Jeśli oddamy go w takim stanie programiście, to pewne jest, że prędzej czy później będzie to jego serwer testowy i dziać się [...]]]></description>
			<content:encoded><![CDATA[<p><a title="http://guzik.net.pl/blog/2008/07/replikacja-baz-mysql/" href="http://forge.mysql.com/wiki/MySQL_Proxy"><img class="alignleft" title="mysql-proxy logo" src="http://forge.mysql.com/w/images/9/93/Sakila_proxy_256x298.jpg" alt="" width="256" height="298" />Replikacja baz MySQL</a> działa jako tako. Jeśli to typ MASTER &#8211; SLAVE, to na ogół ten drugi serwer się nudzi. Skoro się nudzi, można wykorzystać go do zapytań, które nie zmieniają niczego (<a title="http://dev.mysql.com/doc/refman/5.0/en/select.html" href="http://dev.mysql.com/doc/refman/5.0/en/select.html"><code>SELECT</code></a>). Jeśli oddamy go w takim stanie programiście, to pewne jest, że prędzej czy później będzie to jego serwer testowy i dziać się będą na nim różne rzeczy.<br />
<span id="more-1181"></span><br />
Pewnie sposobów na ograniczenie tego jest parę, ja zrobiłem to wykorzystując <a title="http://forge.mysql.com/wiki/MySQL_Proxy" href="http://forge.mysql.com/wiki/MySQL_Proxy">mysql-proxy</a> i odpowiedni skrypt <a title="http://www.lua.org/" href="http://www.lua.org/">Lua</a>. A wygląda to tak:</p>
<blockquote><p><code>function read_query( packet )<br />
--      local log_file = '/var/log/mysql-proxy.log'<br />
--      local fh = io.open(log_file, 'a+')<br />
if string.byte(packet) == proxy.COM_QUERY then<br />
local query = string.sub(packet, 2)<br />
if not (string.match(string.upper(query), '^%s*SELECT') or string.match(string.upper(query), '^%s*SHOW')) then<br />
--                      fh:write(string.format("%s %s\t%s\t%s\t%s\n", os.date('%Y-%m-%d %H:%M:%S'), proxy.connection.client.address, proxy.connection.client.username, proxy.connection.client.default_db, query))<br />
proxy.response.type = proxy.MYSQLD_PACKET_ERR<br />
proxy.response.errmsg = "Only SELECT and SHOW queries are available"<br />
return proxy.PROXY_SEND_RESULT<br />
end<br />
end<br />
--      fh:flush()<br />
end</code></p></blockquote>
<p>W powyższym kodzie zakomentowałem linijki odpowiadające za logowanie wszystkiego, co nie zaczyna się od <code>SELECT</code> lub <code>SHOW</code>.</p>
<p>Przy okazji poznałem głębiej jak działają takie skrypty (<a title="http://guzik.net.pl/blog/2008/07/sprawdzanie-aktywnosci-uzytkownikow-mysql/" href="http://guzik.net.pl/blog/2008/07/sprawdzanie-aktywnosci-uzytkownikow-mysql/">kiedyś coś tam już grzebałem</a>). Do tego doszedłem:</p>
<ul>
<li><a title="http://dev.mysql.com/doc/refman/5.0/en/mysql-proxy-scripting-structures.html#mysql-proxy-scripting-structures-queries" href="http://dev.mysql.com/doc/refman/5.0/en/mysql-proxy-scripting-structures.html#mysql-proxy-scripting-structures-queries"><code>proxy.queries</code></a> to kolejka zapytań, które sami (w skrypcie) stworzymy. <code>reset()</code> nie usunie nam zapytania, które przesyła klient (tym samym <code>len()</code> zawsze pokaże 0),</li>
<li>jeżeli nie będziemy manipulować kolejką, to do serwera zawsze dojdzie to co wysłał klient,</li>
<li>manipulować kolejką możemy poprzez np. <code>append()</code>, a następnie wysyłać zapytania przez <a title="http://dev.mysql.com/doc/refman/5.0/en/mysql-proxy-scripting-structures.html#mysql-proxy-scripting-structures-return-states" href="http://dev.mysql.com/doc/refman/5.0/en/mysql-proxy-scripting-structures.html#mysql-proxy-scripting-structures-return-states"><code>proxy.PROXY_SEND_QUERY</code></a>,</li>
<li>możemy zupełnie pominąć to co wysyła klient i przygotować dla niego <a title="http://dev.mysql.com/doc/refman/5.0/en/mysql-proxy-scripting-structures.html#mysql-proxy-scripting-structures-response" href="http://dev.mysql.com/doc/refman/5.0/en/mysql-proxy-scripting-structures.html#mysql-proxy-scripting-structures-response">własną odpowiedź lub błąd</a> (jak w skrypcie wyżej).</li>
</ul>
<p>Warto zajrzeć na:</p>
<ul>
<li><a title="http://www.lua.org/manual/5.1/manual.html" href="http://www.lua.org/manual/5.1/manual.html">Lua 5.1 Reference Manual</a></li>
<li><a title="http://dev.mysql.com/tech-resources/articles/proxy-gettingstarted.html" href="http://dev.mysql.com/tech-resources/articles/proxy-gettingstarted.html">Getting started with MySQL Proxy</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://guzik.net.pl/blog/2009/11/troche-lua-w-mysql-proxy/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>nagios: check_mysql-replication.pl</title>
		<link>http://guzik.net.pl/blog/2009/10/nagios-check_mysql-replication-pl/</link>
		<comments>http://guzik.net.pl/blog/2009/10/nagios-check_mysql-replication-pl/#comments</comments>
		<pubDate>Thu, 22 Oct 2009 11:27:49 +0000</pubDate>
		<dc:creator>guzik</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[check_mysql-replication]]></category>
		<category><![CDATA[Nagios]]></category>

		<guid isPermaLink="false">http://guzik.net.pl/blog/?p=1139</guid>
		<description><![CDATA[Do monitorowania replikacji MySQL pod Nagios postanowiłem użyć wtyczki mysql_check-replication.pl, ktrej autorem jest Erwan Labynocle Ben Souiden. Instrukcja mówi o nadaniu prawa REPLICATION CLIENT użytkownikowi, który łączył się będzie z bazą. Sam skrypt napisany jest w Perl, gdzie w DSN podana jest baza, do której użytkownik będzie się podłączał. Wspomniane prawa dają tylko możliwość wywołania [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://nagios.org/"><img class="alignright" title="Nagios logo" src="http://assets.nagios.com/images/header/Nagios.png" alt="" width="212" height="50" /></a>Do monitorowania <a title="http://dev.mysql.com/doc/refman/5.0/en/replication.html" href="http://dev.mysql.com/doc/refman/5.0/en/replication.html">replikacji MySQL</a> pod <a title="http://nagios.org/" href="http://nagios.org/">Nagios</a> postanowiłem użyć <a title="http://exchange.nagios.org/directory/Plugins/Databases/MySQL/check_mysql%252Dreplication-2Epl/details" href="http://exchange.nagios.org/directory/Plugins/Databases/MySQL/check_mysql%252Dreplication-2Epl/details">wtyczki mysql_check-replication.pl</a>, ktrej autorem jest <a title="http://www.aleikoum.net/" href="http://www.aleikoum.net/">Erwan Labynocle Ben Souiden</a>. Instrukcja mówi o nadaniu prawa <a title="http://dev.mysql.com/doc/refman/5.0/en/privileges-provided.html#priv_replication-client" href="http://dev.mysql.com/doc/refman/5.0/en/privileges-provided.html#priv_replication-client">REPLICATION CLIENT</a> użytkownikowi, który łączył się będzie z bazą. Sam skrypt napisany jest w <a title="http://www.perl.org/" href="http://www.perl.org/">Perl</a>, gdzie w DSN podana jest baza, do której użytkownik będzie się podłączał. Wspomniane prawa dają tylko możliwość wywołania <a title="http://dev.mysql.com/doc/refman/5.0/en/show-master-status.html" href="http://dev.mysql.com/doc/refman/5.0/en/show-master-status.html">SHOW MASTER STATUS</a> oraz <a title="http://dev.mysql.com/doc/refman/5.0/en/show-slave-status.html" href="http://dev.mysql.com/doc/refman/5.0/en/show-slave-status.html">SHOW SLAVE STATUS</a> i nie dają praw do <span style="text-decoration: underline;">żadnej</span> bazy. Tym samym skrypt się nie wykona.</p>
<p>Proponuję (wersja 0.1) przerobić DSN (linia 298) i wyrzucić nazwę bazy zupełnie (pozostawić `:&#8217; &#8211; dwukropek) lub zmienić nazwę na <a title="http://dev.mysql.com/doc/refman/5.0/en/information-schema.html" href="http://dev.mysql.com/doc/refman/5.0/en/information-schema.html"><code>information_schema</code></a>, bo do tego prawo ma każdy użytkownik (dla wersji &gt; 5.0).</p>
<blockquote><p><code>--- /usr/lib64/nagios/plugins/check_mysql-replication.pl        2009-10-22 13:17:26.000000000 +0200<br />
+++ check_mysql-replication.pl  2009-10-22 13:17:33.000000000 +0200<br />
@@ -295,7 +295,7 @@ EOT<br />
# ------------------------------<br />
sub request_executor() {<br />
my ($host,$port,$user,$pwd,$request) = @_;<br />
-    my $dsn = "DBI:mysql:mysql;host=$host:$port";<br />
+    my $dsn = "DBI:mysql:;host=$host:$port";<br />
my $dbh = DBI-&gt;connect($dsn, $user, $pwd) or die "connexion failed $DBI::errstr\n";<br />
my $sth = $dbh-&gt;prepare($request);<br />
$sth-&gt;execute();</code></p></blockquote>
<p>Autor obiecał, że wprowadzi stosowną poprawkę &#8211; tymczasem można łatać.</p>
]]></content:encoded>
			<wfw:commentRss>http://guzik.net.pl/blog/2009/10/nagios-check_mysql-replication-pl/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MySQL slow_queries</title>
		<link>http://guzik.net.pl/blog/2009/02/mysql-slow_queries/</link>
		<comments>http://guzik.net.pl/blog/2009/02/mysql-slow_queries/#comments</comments>
		<pubDate>Tue, 10 Feb 2009 19:49:15 +0000</pubDate>
		<dc:creator>guzik</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[slow-queries]]></category>

		<guid isPermaLink="false">http://guzik.net.pl/blog/?p=550</guid>
		<description><![CDATA[Już kiedyś płakałem z tego powodu &#8211; Analiza log-slow-queries (z życia wzięte…), a tu stary klient narzeka na wydajność swojego serwera. I co my tu mamy? tabela 1 &#8211; 117&#8217;608 wierszy, tabela 2 &#8211; 730 wierszy, tabela 3 &#8211; 709 wierszy. Niby niewiele, ale da się z tego zrobić taki wynik: # Query_time: 11'005  Lock_time: [...]]]></description>
			<content:encoded><![CDATA[<p>Już kiedyś płakałem z tego powodu &#8211; <a title="http://guzik.net.pl/blog/2008/07/analiza-log-slow-queries-z-zycia-wziete/" href="http://guzik.net.pl/blog/2008/07/analiza-log-slow-queries-z-zycia-wziete/">Analiza log-slow-queries (z życia wzięte…)</a>, a tu stary klient narzeka na wydajność swojego serwera. I co my tu mamy?</p>
<ul>
<li> tabela 1 &#8211; 117&#8217;608 wierszy,</li>
<li>tabela 2 &#8211; 730 wierszy,</li>
<li>tabela 3 &#8211; 709 wierszy.</li>
</ul>
<p>Niby niewiele, ale da się z tego zrobić taki wynik:</p>
<blockquote><p><code># Query_time: 11'005  Lock_time: 0  Rows_sent: 1  Rows_examined: 88'891'086</code></p></blockquote>
<p>Dla porównania 10 miesięcy temu to samo zapytanie:</p>
<blockquote><p><code># Query_time: 53  Lock_time: 0  Rows_sent: 615  Rows_examined: 8'674'949</code></p></blockquote>
<p>Nie mam pytań. Zdecydowanie potrzeba nowego procesora, więcej pamięci i szybszych dysków. Programisty przecież nie przekonamy&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://guzik.net.pl/blog/2009/02/mysql-slow_queries/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SQL Relay</title>
		<link>http://guzik.net.pl/blog/2008/09/sql-relay/</link>
		<comments>http://guzik.net.pl/blog/2008/09/sql-relay/#comments</comments>
		<pubDate>Thu, 04 Sep 2008 05:57:49 +0000</pubDate>
		<dc:creator>guzik</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[SQL Relay]]></category>

		<guid isPermaLink="false">http://guzik.net.pl/blog/?p=64</guid>
		<description><![CDATA[Zajmował się ktoś SQL Relay? Wygląda obiecująco, i te wsparcie dostawców &#8211; Oracle, MySQL, mSQL, PostgreSQL, Sybase, MS SQL Server (oba przez FreeTDS), IBM DB2, Interbase, SQLite, ODBC, MS Access (MDB Tools)&#8230; Postanowiłem przyjrzeć się temu w połączeniu z PostgreSQL i MySQL z C/C++ i Perl API. Wersja 0.39.4. Jest w portach dla FreeBSD, nie [...]]]></description>
			<content:encoded><![CDATA[<p>Zajmował się ktoś <a title="http://sqlrelay.sourceforge.net/" href="http://sqlrelay.sourceforge.net/">SQL Relay</a>? Wygląda obiecująco, i te wsparcie dostawców &#8211; <a title="http://www.oracle.com/index.html" href="http://www.oracle.com/index.html">Oracle</a>, <a title="http://dev.mysql.com/" href="http://dev.mysql.com/">MySQL</a>, <a title="http://www.hughes.com.au/products/msql/" href="http://www.hughes.com.au/products/msql/">mSQL</a>, <a title="http://www.postgresql.org/" href="http://www.postgresql.org/">PostgreSQL</a>, <a title="http://www.sybase.com/" href="http://www.sybase.com/">Sybase</a>, <a title="http://www.microsoft.com/sqlserver/2008/en/us/default.aspx" href="http://www.microsoft.com/sqlserver/2008/en/us/default.aspx">MS SQL Server</a> (oba przez <a title="http://www.freetds.org/" href="http://www.freetds.org/">FreeTDS</a>), <a title="http://www.ibm.com/db2" href="http://www.ibm.com/db2">IBM DB2</a>, <a title="http://www.codegear.com/products/interbase" href="http://www.codegear.com/products/interbase">Interbase</a>, <a title="http://www.sqlite.org/" href="http://www.sqlite.org/">SQLite</a>, <a title="http://pl.wikipedia.org/wiki/ODBC" href="http://pl.wikipedia.org/wiki/ODBC">ODBC</a>, <a title="http://office.microsoft.com/pl-pl/access/default.aspx" href="http://office.microsoft.com/pl-pl/access/default.aspx">MS Access</a> (<a title="http://mdbtools.sourceforge.net/" href="http://mdbtools.sourceforge.net/">MDB Tools</a>)&#8230;</p>
<p>Postanowiłem przyjrzeć się temu w połączeniu z PostgreSQL i MySQL z C/C++ i Perl API. Wersja 0.39.4.<br />
Jest w portach dla <a title="http://www.freebsd.org/" href="http://www.freebsd.org/">FreeBSD</a>, nie ma w paczkach dla <a title="http://www.gentoo.org/" href="http://www.gentoo.org/">Gentoo</a>. Potrzebuje dodatkowej biblioteki <a title="http://rudiments.sourceforge.net/" href="http://rudiments.sourceforge.net/">Rudiments</a> (<a title="http://www.freshports.org/devel/rudiments/" href="http://www.freshports.org/devel/rudiments/">devel/rudiments</a> we FreeBSD, <a title="http://packages.gentoo.org/package/dev-cpp/rudiments" href="http://packages.gentoo.org/package/dev-cpp/rudiments">dev-cpp/rudiments</a> w Gentoo) i jeśli chcemy jakiegoś API, to odpowiednio: <a href="http://www.perl.org/">Perl</a>,  <a href="http://www.php.org/">PHP</a>, <a href="http://www.python.org/">Python</a>, <a href="http://www.ruby-lang.org/">Ruby</a>, <a href="http://tcl.sourceforge.net/">TCL</a>, <a href="http://java.sun.com/">Java</a> lub <a href="http://www.zope.org/">Zope</a>. <a title="http://www.gtk.org/" href="http://www.gtk.org/">GTK+</a> i glib  da nam GUI.</p>
<p>Konfiguracja nietrudna &#8211; w pliku XML. W <em>tagu</em> <strong>instance</strong> definiujemy proces nasłuchu. <em>Tag</em> <strong>user</strong> to definicje użytkowników wraz z hasłami. Na koniec <em>tag</em> <strong>connection</strong>, który wskazuje konfigurację do konkretnej bazy.<br />
W bardziej złożonej konfiguracji mamy jeszcze <strong>router</strong> i <strong>filter</strong>. Pierwszy <em>tag</em> odpowiada za kierowanie zapytań do odpowiedniej bazy, drugi &#8211; za filtrowanie zapytań (zdefiniowane nie będą w ogóle przesyłane do serwera, a klient dostanie błąd). W obu przypadkach jest możliwość dopasowania zapytań za pomocą wyrażeń regularnych.</p>
<p>Jeżeli uruchamiamy SQL Relay za pomocą sqlr-start, musimy pamiętać, że wszystkie programy, które wywołuje, np. sqlr-listener muszą być w ścieżce ($PATH). Baza również musi działać. Jeśli nie, pozostaje walka z czyszczeniem <em>shared memory segment</em> i <em>semaphore</em> (ipcs, ipcrm), bo SQL Relay nie sprząta po sobie.</p>
<p>Na tym skończyłem walkę. To znaczy próbowałem uruchomić SQL Relay zarówno z MySQL jak i PostgreSQL, ale niestety zakończyło się to niepowodzeniem (SQL Relay nasłuchiwał, przy połączeniu cisza). Mam nadzieję, że kiedyś wrócę do tego tematu.</p>
<p>Przepraszam, jeśli ktoś był pełen nadzieji, że czegoś się dowie z tego artykułu. Zmieniłem pracę i już nie robię tego co robiłem, więc wiele rzeczy pozostało niedokończonych&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://guzik.net.pl/blog/2008/09/sql-relay/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Bezpieczne połączenia z MySQL (C API)</title>
		<link>http://guzik.net.pl/blog/2008/08/bezpieczne-polaczenia-z-mysql-c-api/</link>
		<comments>http://guzik.net.pl/blog/2008/08/bezpieczne-polaczenia-z-mysql-c-api/#comments</comments>
		<pubDate>Sun, 10 Aug 2008 20:40:16 +0000</pubDate>
		<dc:creator>guzik</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[C API]]></category>
		<category><![CDATA[mysql_ssl_set]]></category>
		<category><![CDATA[SSL]]></category>

		<guid isPermaLink="false">http://guzik.net.pl/blog/?p=158</guid>
		<description><![CDATA[Ostatnio coraz więcej kodu w C piszę z użyciem MySQL API, a że dane przy jednym z projektów są poufne i serwer nie jest lokalny, przyjrzałem się połączeniom SSL. W zasadzie po stronie kodu to nic wielkiego &#8211; wystarczy wywołać mysql_ssl_set() przed mysql_real_connect() (mysql_connect() jest deprecated). Oczywiście pod warunkiem, że klient jest skompilowany ze wsparciem [...]]]></description>
			<content:encoded><![CDATA[<p>Ostatnio coraz więcej kodu w C piszę z użyciem <a title="http://dev.mysql.com/doc/refman/5.0/en/c.html" href="http://dev.mysql.com/doc/refman/5.0/en/c.html">MySQL API</a>, a że dane przy jednym z projektów są poufne i serwer nie jest lokalny, przyjrzałem się połączeniom SSL. W zasadzie po stronie kodu to nic wielkiego &#8211; wystarczy wywołać <a title="http://dev.mysql.com/doc/refman/5.0/en/mysql-ssl-set.html" href="http://dev.mysql.com/doc/refman/5.0/en/mysql-ssl-set.html"><code>mysql_ssl_set()</code></a> przed <a title="http://dev.mysql.com/doc/refman/5.0/en/mysql-real-connect.html" href="http://dev.mysql.com/doc/refman/5.0/en/mysql-real-connect.html"><code>mysql_real_connect()</code></a> (<code>mysql_connect()</code> jest <em>deprecated</em>). Oczywiście pod warunkiem, że klient jest skompilowany ze wsparciem <a title="http://openssl.org/" href="http://openssl.org/">OpenSSL</a> (lub <a title="http://www.yassl.com/" href="http://www.yassl.com/">yaSSL</a>, ale nigdy nie testowałem).</p>
<p>Uruchomienie samego serwera (również przy założeniu, że skompilowany ze wsparciem SSL) sprowadza się do podania <a title="http://dev.mysql.com/doc/refman/5.0/en/ssl-options.html" href="http://dev.mysql.com/doc/refman/5.0/en/ssl-options.html">dodatkowych parametrów</a> w linii komend. Przykładowo może to wyglądać tak:</p>
<blockquote><p><code>mysqld --defaults-file=/etc/mysql/my.cnf --ssl --ssl-ca=&lt;/path/to/CA.crt&gt; --ssl-cert=&lt;/path/to/file.crt&gt; --ssl-key=&lt;/path/to/file.key&gt;</code></p></blockquote>
<p>Ewentualnie odpowiednie parametry podać w pliku konfiguracyjnym (<code>my.cnf</code>):</p>
<blockquote><p><code>ssl-ca = &lt;/path/to/CA.crt&gt;<br />
ssl-cert =&lt;/path/to/file.crt&gt;<br />
ssl-key =&lt;/path/to/file.key&gt;</code></p></blockquote>
<p>Pamiętać należy, że w przypadku, gdy certyfikat jest zabezpieczony hasłem, MySQL może być jedynie uruchomiony ręcznie. Korzystając ze skryptów startowych (na pewno w Gentoo Linux) czy nawet wrzucając proces w tło (<code>&amp;</code>) serwer nie skorzysta z certyfikatu i nie nawiążemy szyfrowanej transmisji. Próba takiego uruchomienia zakończy się podobnym wpisem w logach:</p>
<blockquote><p><code>[Warning] Failed to setup SSL</code></p></blockquote>
<p>Testowe połączenie do serwera z konsoli mysql możemy wykonać podając jedynie ścieżkę do certyfikatu CA (format PEM), np.</p>
<blockquote><p><code>mysql -h &lt;host&gt; -u &lt;user&gt; -p --ssl-ca=&lt;/path/to/CA.crt&gt; &lt;database&gt;</code></p></blockquote>
<p>Wywołując <code>STATUS </code>możemy sprawdzić czy bieżące połączenie ma wsparcie SSL:</p>
<blockquote><p><code>SSL:            Cipher in use is DHE-RSA-AES256-SHA</code></p></blockquote>
<p>czy też nie:</p>
<blockquote><p><code>SSL:            Not in use</code></p></blockquote>
<p>Wymuszanie szyfrowanych połączeń możliwe tylko poprzez <code>REQUIRE SSL</code> przy nadawaniu praw użytkownikowi (<a title="http://dev.mysql.com/doc/refman/5.0/en/grant.html" href="http://dev.mysql.com/doc/refman/5.0/en/grant.html"><code>GRANT</code></a>). W takim przypadku połączenie bez SSL zakończy się komunikatem podobnym jak w przypadku np. podania błędnego hasła:</p>
<blockquote><p><code>ERROR 1045 (28000): Access denied for user 'exg'@'192.168.1.101' (using p assword: YES)</code></p></blockquote>
<p>Więcej o używaniu SSL w MySQL można poczytać tutaj:</p>
<ul>
<li><a title="http://dev.mysql.com/doc/refman/5.0/en/secure-using-ssl.html" href="http://dev.mysql.com/doc/refman/5.0/en/secure-using-ssl.html">MySQL 5.0 Reference Manual :: 5.5.7.2 Using SSL Connections</a></li>
</ul>
<p>Wracając do samej funkcji <code>mysql_ssl_set()</code>, to jako parametry przyjmuje: uchwyt połączenia zwrócony przez <a title="http://dev.mysql.com/doc/refman/5.0/en/mysql-init.html" href="http://dev.mysql.com/doc/refman/5.0/en/mysql-init.html"><code>mysql_init()</code></a>, ścieżkę do pliku klucza, certyfikatu i certyfikatu CA oraz ścieżkę do katalogu z certyfikatami CA w formacie PEM, a także listę wspieranych algorytmów.<br />
Nieużywane parametry powinny przyjmować wartość <code>NULL</code>.<br />
Funkcja zawsze zwraca <code>0</code>, o błędach SSL informuje <code>mysql_real_connect()</code>.</p>
<blockquote><p><code>ERROR 2026 (HY000): SSL connection error</code></p></blockquote>
<p>Na koniec łyżka dziegciu &#8211; libmysql (i klient mysql) dla Windows (ten z binarnej paczki) nie jest skompilowany z obsługą SSL. Aby korzystać z bezpiecznych połączeń należy pobrać źródła i samodzielnie dokonać kompilacji. Mi się nie udało&#8230; Może przez zbyt stare Visual C++.</p>
]]></content:encoded>
			<wfw:commentRss>http://guzik.net.pl/blog/2008/08/bezpieczne-polaczenia-z-mysql-c-api/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Analiza log-slow-queries (z życia wzięte&#8230;)</title>
		<link>http://guzik.net.pl/blog/2008/07/analiza-log-slow-queries-z-zycia-wziete/</link>
		<comments>http://guzik.net.pl/blog/2008/07/analiza-log-slow-queries-z-zycia-wziete/#comments</comments>
		<pubDate>Sat, 26 Jul 2008 11:21:03 +0000</pubDate>
		<dc:creator>guzik</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[log-slow-queries]]></category>

		<guid isPermaLink="false">http://guzik.net.pl/blog/?p=74</guid>
		<description><![CDATA[Jedna z tabel klienta wygląda tak: CREATE TABLE `mix_stats` ( `id` int(11) NOT NULL auto_increment, `id_produktu` decimal(20,0) NOT NULL default &#8217;0&#8242;, `data` date default NULL, `count` decimal(1,0) NOT NULL default &#8217;0&#8242;, `session` varchar(255) NOT NULL default &#8221;, `ip` varchar(20) NOT NULL default &#8221;, `referer` varchar(255) NOT NULL default &#8221;, PRIMARY KEY  (`id`) ) TYPE=MyISAM MySQL [...]]]></description>
			<content:encoded><![CDATA[<p>Jedna z tabel klienta wygląda tak:</p>
<blockquote><p>CREATE TABLE `mix_stats` (<br />
`id` int(11) NOT NULL auto_increment,<br />
`id_produktu` decimal(20,0) NOT NULL default &#8217;0&#8242;,<br />
`data` date default NULL,<br />
`count` decimal(1,0) NOT NULL default &#8217;0&#8242;,<br />
`session` varchar(255) NOT NULL default &#8221;,<br />
`ip` varchar(20) NOT NULL default &#8221;,<br />
`referer` varchar(255) NOT NULL default &#8221;,<br />
PRIMARY KEY  (`id`)<br />
) TYPE=MyISAM</p></blockquote>
<p>MySQL 3.23, w logach następujące wpisy:</p>
<blockquote><p># Time: 080726 10:40:51<br />
# User@Host: xxx[xxx] @ localhost []<br />
# Query_time: 48  Lock_time: 0  Rows_sent: 1  Rows_examined: 639552<br />
SELECT count(id) FROM mix_stats WHERE id_produktu = &#8217;84092324382e93e&#8217; AND session = &#8221;;</p></blockquote>
<p>Jeżeli ktoś jest na tyle cierpliwy, by czekać 48 sekund na wynik, to musi mu bardzo zależeć&#8230;</p>
<p>Analizę bazy wykonywałem na MySQL 5.0.60, więc mam większe pole do popisu, np.:</p>
<blockquote>
<pre>mysql&gt; SELECT count(id) FROM mix_stats WHERE id_produktu = '84092324382e93e' AND session = '';
+-----------+
| count(id) |
+-----------+
|         0 |
+-----------+
1 row in set, 65535 warnings (0.99 sec)

mysql&gt; <a title="http://dev.mysql.com/doc/refman/5.0/en/show-warnings.html" href="http://dev.mysql.com/doc/refman/5.0/en/show-warnings.html">SHOW WARNINGS</a> LIMIT 3;
+---------+------+-----------------------------------------------------+
| Level   | Code | Message                                             |
+---------+------+-----------------------------------------------------+
| Warning | 1292 | Truncated incorrect DOUBLE value: '84092324382e93e' |
| Warning | 1292 | Truncated incorrect DOUBLE value: '84092324382e93e' |
| Warning | 1292 | Truncated incorrect DOUBLE value: '84092324382e93e' |
+---------+------+-----------------------------------------------------+
3 rows in set (0.00 sec)</pre>
</blockquote>
<p>Na początek polecam: <a title="http://dev.mysql.com/doc/refman/5.0/en/numeric-types.html" href="http://dev.mysql.com/doc/refman/5.0/en/numeric-types.html">DECIMAL</a>. Choć pewnie skończy się przejściem do innego usługodawcy, gdzie mocniejsza maszyna bazodanowa przemieli to szybciej (ostrzeżenia i błędy i tak użytkowników nie interesują)&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://guzik.net.pl/blog/2008/07/analiza-log-slow-queries-z-zycia-wziete/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>MySQL vs. PostgreSQL (adresy IP)</title>
		<link>http://guzik.net.pl/blog/2008/07/mysql-vs-postgresql-adresy-ip/</link>
		<comments>http://guzik.net.pl/blog/2008/07/mysql-vs-postgresql-adresy-ip/#comments</comments>
		<pubDate>Mon, 21 Jul 2008 14:19:22 +0000</pubDate>
		<dc:creator>guzik</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[cidr]]></category>
		<category><![CDATA[inet]]></category>
		<category><![CDATA[INET_ATON]]></category>
		<category><![CDATA[INET_NTOA]]></category>
		<category><![CDATA[macaddr]]></category>

		<guid isPermaLink="false">http://guzik.net.pl/blog/?p=51</guid>
		<description><![CDATA[Jeżeli kiedykolwiek zastanawialiśmy się jak przechowywać i łatwo przetwarzać adresy IP w bazie danych MySQL, odpowiedź brzmi &#8211; zmienić bazę na PostgreSQL (i nie tylko w tym przypadku). MySQL oprócz funkcji INET_ATON() i INET_NTOA() nie oferuje nic więcej, ale to i tak lepsze niż przechowywanie adresów w CHAR(15) czy VARCHAR(15). Wskazany typ kolumny to UNSIGNED [...]]]></description>
			<content:encoded><![CDATA[<p>Jeżeli kiedykolwiek zastanawialiśmy się jak przechowywać i łatwo przetwarzać adresy IP w bazie danych <a title="http://dev.mysql.com/" href="http://dev.mysql.com/">MySQL</a>, odpowiedź brzmi &#8211; zmienić bazę na <a title="http://www.postgresql.org/" href="http://www.postgresql.org/">PostgreSQL</a> (i nie tylko w tym przypadku).</p>
<p>MySQL oprócz funkcji <a title="http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_inet-aton" href="http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_inet-aton">INET_ATON()</a> i <a title="http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_inet-ntoa" href="http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_inet-ntoa">INET_NTOA()</a> nie oferuje nic więcej, ale to i tak lepsze niż przechowywanie adresów w CHAR(15) czy <a title="http://dev.mysql.com/doc/refman/5.0/en/char.html" href="http://dev.mysql.com/doc/refman/5.0/en/char.html">VARCHAR(15)</a>. Wskazany typ kolumny to <a title="http://dev.mysql.com/doc/refman/5.0/en/numeric-types.html" href="http://dev.mysql.com/doc/refman/5.0/en/numeric-types.html">UNSIGNED INT</a>, a konwersja przy wstawianiu rekordów czy ich pobieraniu właśnie za pomocą wspomnianych funkcji.</p>
<p>PostgreSQL daje nam następujące typy danych: <a title="http://www.postgresql.org/docs/8.3/interactive/datatype-net-types.html" href="http://www.postgresql.org/docs/8.3/interactive/datatype-net-types.html">cidr</a>, inet i dodatkowo macaddr (do przechowywania adresów MAC). Umożliwia także łatwe zarządzanie danymi za pomocą operatorów i <a title="http://www.postgresql.org/docs/8.3/interactive/functions-net.html" href="http://www.postgresql.org/docs/8.3/interactive/functions-net.html">funkcji</a>.</p>
<p>Oczywiście sposób przechowywania adresu IP na pewno nie powinien być kryterium wyboru silnika baz danych, ale może być drobnym argumentem.</p>
<p>Do przeanalizowania kwestia szybkości przeszukiwania, indeksowania i wielkości danych.</p>
<p>Do poczytania:</p>
<ul>
<li><a title="http://arjen-lentz.livejournal.com/44290.html" href="http://arjen-lentz.livejournal.com/44290.html">Arjen&#8217;s Journal &#8211; Storing an IP address in a database table</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://guzik.net.pl/blog/2008/07/mysql-vs-postgresql-adresy-ip/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Sprawdzanie aktywności użytkowników MySQL</title>
		<link>http://guzik.net.pl/blog/2008/07/sprawdzanie-aktywnosci-uzytkownikow-mysql/</link>
		<comments>http://guzik.net.pl/blog/2008/07/sprawdzanie-aktywnosci-uzytkownikow-mysql/#comments</comments>
		<pubDate>Fri, 18 Jul 2008 10:16:13 +0000</pubDate>
		<dc:creator>guzik</dc:creator>
				<category><![CDATA[DB]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[LUA]]></category>
		<category><![CDATA[mysql-proxy]]></category>

		<guid isPermaLink="false">http://guzik.net.pl/blog/?p=32</guid>
		<description><![CDATA[Podłoże problemu: bazy zakładane na serwerze na żądanie użytkowników / klientów nie były usuwane. Po pewnym czasie ilość baz urosła, z czego spory odsetek była nieużywana. Nie obciąża to serwera, ale zabiera miejsce na dysku i ogólnie powoduje bałagan. Trzeba to jakoś posprzątać! Prosty sposób &#8211; REVOKE i telefon. Mało elegancki! My szukamy czegoś na [...]]]></description>
			<content:encoded><![CDATA[<p>Podłoże problemu: bazy zakładane na serwerze na żądanie użytkowników / klientów nie były usuwane. Po pewnym czasie ilość baz urosła, z czego spory odsetek była nieużywana. Nie obciąża to serwera, ale zabiera miejsce na dysku i ogólnie powoduje bałagan. Trzeba to jakoś posprzątać!</p>
<p>Prosty sposób &#8211; <a title="http://dev.mysql.com/doc/refman/5.0/en/revoke.html" href="http://dev.mysql.com/doc/refman/5.0/en/revoke.html">REVOKE</a> i telefon. Mało elegancki! My szukamy czegoś na poziomie ;-)</p>
<p>Od pewnego czasu śledzę projekt <a title="http://forge.mysql.com/wiki/MySQL_Proxy" href="http://forge.mysql.com/wiki/MySQL_Proxy">mysql-proxy</a>. Wprawdzie już jakiś czas projekt jest nieuaktualniany (<em>At revision 511.</em>), ale mam nadzieję, że <a title="http://jan.kneschke.de/" href="http://jan.kneschke.de/">Jan Kneschke</a> cały czas pracuje&#8230;</p>
<p>Początkowo używałem mysql-proxy jako typowego pośrednika, co było pomocne przy przenoszeniu baz (sporo klientów łączyło się przez <em>UNIX socket</em>). Nie sprawdzał się za dobrze (ostatnia testowana wersja nie zawsze łączyła z PHP, wcześniejsze miały duże problemy ze stabilną pracą w ogóle). Na podobny projekt &#8211; <a title="http://pgpool.projects.postgresql.org/" href="http://pgpool.projects.postgresql.org/">pgpool-II</a> (dla <a title="http://www.postgresql.org/" href="http://www.postgresql.org/">PostgreSQL</a>) nie narzekałem nigdy. Niemniej z racji długości życia nie ma ich co porównywać.</p>
<p>Dla śledzenia użytkowników z tematu napisałem skrypt (<a title="http://www.lua.org/" href="http://www.lua.org/">LUA</a>), który każde połączenie zapisuje do pliku dziennika (można przerobić na zapisywanie do bazy + jakiś licznik). Informacją wystarczającą jest IP klienta, nazwa użytkownika oraz baza, do której się podłączył. Do posprzątania nic więcej nas nie interesuje.<br />
Sposób uruchomienia mysql-proxy opisany jest w dokumentacji, więc warto tam zajrzeć.<br />
Skrypt wygląda tak:</p>
<blockquote><p>local log_file = &#8216;/tmp/mysql.log&#8217;<br />
local fh = io.open(log_file, &#8222;a+&#8221;)</p>
<p>function read_auth_result(auth)<br />
if auth.packet:byte() == proxy.MYSQLD_PACKET_OK then<br />
fh:write(<br />
string.format(&#8222;%s %s\t%s\t%s\n&#8221;,<br />
os.date(&#8216;%Y-%m-%d %H:%M:%S&#8217;),<br />
proxy.connection.client.address,<br />
proxy.connection.client.username,<br />
proxy.connection.client.default_db))<br />
end<br />
fh:flush()<br />
end</p></blockquote>
<p>Ze struktury <em>proxy.connection.client</em> przyda nam się <em>address</em> (adres IP klienta), <em>username</em> (nazwa uzytkownika) oraz <em>default_db</em> (baza, do której zostało wykonane połączenie). Jest jeszcze <em>scrambled_password</em>, ale logowanie tego podpada pod <a title="http://portalwiedzy.onet.pl/polszczyzna.html?qs=inwigilacja&amp;tr=pol-pol&amp;ch=1&amp;x=0&amp;y=0" href="http://portalwiedzy.onet.pl/polszczyzna.html?qs=inwigilacja&amp;tr=pol-pol&amp;ch=1&amp;x=0&amp;y=0">inwigilację</a>. Logujemy <span style="text-decoration: underline;">tylko</span> uwierzytelnionych użytkowników (MYSQLD_PACKET_OK &#8211; 0, ale jest jeszcze możliwość użycia MYSQLD_PACKET_ERR &#8211; 255). I w wyniku otrzymujemy:</p>
<blockquote><p>2008-07-18 11:52:40 127.0.0.1:43228    root    test<br />
2008-07-18 12:00:16 127.0.0.1:62133    exg    exg<br />
2008-07-18 12:00:32 127.0.0.1:62901    root    mysql<br />
2008-07-18 12:07:54 10.74.0.254:11243	guzik<br />
2008-07-18 12:08:00 10.74.0.254:16369	guzik	test</p></blockquote>
<p>Log bez bazy, to połączenie z konsoli. <em>\u</em> czy <em>USE</em> nie loguje się w ogóle.<br />
Po długoterminowym zbieraniu informacji (do miesiąca) mamy już listę wykorzystywanych baz. Pozostaje <a title="http://dev.mysql.com/doc/refman/5.0/en/mysqldump.html" href="http://dev.mysql.com/doc/refman/5.0/en/mysqldump.html"><em>dump</em></a> i <a title="http://dev.mysql.com/doc/refman/5.0/en/drop-database.html" href="http://dev.mysql.com/doc/refman/5.0/en/drop-database.html">DROP</a> :&gt;</p>
<p>Pamiętajmy też, że baza widzi połączenie z <em>mysql-proxy</em>, więc należy dać stosowne uprawnienia dla tego hosta.</p>
<p>Więcej do poczytania:</p>
<ul>
<li> <a title="http://dev.mysql.com/doc/refman/5.0/en/mysql-proxy-scripting.html" href="http://dev.mysql.com/doc/refman/5.0/en/mysql-proxy-scripting.html">MySQL ::   MySQL 5.0 Reference Manual :: 16.4 MySQL Proxy Scripting</a></li>
<li> <a title="http://dev.mysql.com/tech-resources/articles/proxy-gettingstarted.html" href="http://dev.mysql.com/tech-resources/articles/proxy-gettingstarted.html">MySQL ::  Getting started with MySQL Proxy</a></li>
<li> <a title="http://mystic-one.com/2008/05/13/partial-mysql-proxy-api-doc/" href="http://mystic-one.com/2008/05/13/partial-mysql-proxy-api-doc/">Mystic&#8217;s Random Blog » (partial) MySQL Proxy API Doc</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://guzik.net.pl/blog/2008/07/sprawdzanie-aktywnosci-uzytkownikow-mysql/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
