Posts with tag Python

Testování rychlosti dotazů v MySQL 5.1

Nov|26 2009

V příspěvku jsou popsány základní možnosti, jak zjišťovat rychlost a efektivitu různých SQL dotazů, za účelem výběru nejoptimálnějšího řešení.

Nejdříve něco málo o testování rychlosti dotazů v MySQL. Rychlost dotazů testujeme nejčastěji u sestavování složitějších dotazů, často doprovázené spojováním více tabulek. Pomocí PhpMyAdminu nebo konzole můžeme vytvářet libovolné dotazy a rychlost jejich zpracování je po provedení uvedena.

Musím hned zpočátku upozornit, abyste si předem velmi rozmysleli, jaký dotaz provádíte, pokud to není na vašem stroji, můžete nešikovným dotazem SQL server pěkně potrápit. V případě pochybností nebo i preventivně doporučuji použít na dotaz omezení pomocí LIMIT. To většinou zabrzdí vykonávání dotazu včas.

Při testování rychlosti dotazů často narážíme na první problém - využívání cache. Pokud podobný dotaz provádíme vícekrát nebo jsou data v paměti SQL serveru, výsledky jsou k dispozici rychleji a o složitosti dotazu se mnoho nedozvíme. Zakázat využití cache paměti lze doplněním klíčového slova SQL_NO_CACHE ihned za první SELECT. Tím bychom měli přemluvit server, aby nepoužíval cache.


SELECT SQL_NO_CACHE *
FROM `produkty`
WHERE price > 1000
ORDER BY `name` ASC
limit 10;

Pro pochopení, jak zpracovává složitější dotaz SQL server, lze využívat příkaz EXPLAIN, který se jednoduše přidá před zkoumaný dotaz.


EXPLAIN SELECT *
FROM `produkty`
WHERE price > 1000
ORDER BY `name` ASC
limit 10;

Pokud ale hledáme ideální řešení a vybíráme mezi více dotazy, které se liší strukturou, ale vracejí stejná data, příkaz EXPLAIN nám toho moc neřekne, místo něho je lepší použít proměnou last_query_cost. Optimalizátor tuto hodnotu nastaví vždy při vykonání nějakého dotazu v daném sezení a obsahuje nějaké číslo. Čím větší číslo, tím složitější dotaz.


SELECT *
FROM `produkty`
WHERE price > 1000
ORDER BY `name` ASC
limit 10;
SHOW SESSION STATUS WHERE Variable_name LIKE 'last_query_cost';

Samozřejmě mi nedá abych nepřipomenul, že velkou práci databázovému serveru ušetříte správným používáním indexů. Nakonec přikládám malý prográmek v Pythonu 3, který generuje náhodné hodnoty do tabulek produkty a atributy. Definice tabulek je následující:


CREATE TABLE IF NOT EXISTS `atributy` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`produkt` int(11) NOT NULL,
`type` int(11) NOT NULL,
`value_number` int(11) DEFAULT NULL,
`value_text` text COLLATE utf8_czech_ci,
`value_datetime` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `produkt` (`produkt`,`type`)
) ENGINE=InnoDB;


CREATE TABLE IF NOT EXISTS `produkty` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(200) COLLATE utf8_czech_ci NOT NULL,
`price` decimal(8,2) NOT NULL,
`active` int(11) NOT NULL,
`text` text COLLATE utf8_czech_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;

A slíbený program je zde:


import random

alphabet = 'abcdefghijklmnopqrstuvwxz '

def getString(mn, mx):
"""
Generate random string with the length between mn and mx.
"""
s = ''
for i in range(random.randint(mn, mx)):
s += alphabet[random.randint(0, len(alphabet) -1)]
return s

# generates data for table produkty
for i in range(1000):
print('INSERT INTO `produkty` (`id`, `name`, `price`, `active`, `text`) '
+ 'VALUES (NULL, \'%s\', \'%s\', %s, \'%s\');'
% (getString(3, 20), str(random.randint(10, 1000)),
str(random.randint(0, 1)), getString(50, 500)))

# generates data for table atributy
for i in range(1000):
for j in range(5):
print('INSERT INTO `atributy` '
+ '(`id`, `produkt`, `type`, `value_number`, `value_text`, `value_datetime`) '
+ 'VALUES (NULL, \'%s\', \'%s\', %s, \'NULL\', \'NULL\');'
% (str(i), '2', str(random.randint(10, 1000))))
print('INSERT INTO `atributy` '
+ '(`id`, `produkt`, `type`, `value_number`, `value_text`, `value_datetime`) '
+ 'VALUES (NULL, \'%s\', \'%s\', \'NULL\', \'%s\', \'NULL\');'
% (str(i), '3', getString(10, 1000)))
print('INSERT INTO `atributy` '
+ '(`id`, `produkt`, `type`, `value_number`, `value_text`, `value_datetime`) '
+ 'VALUES (NULL, \'%s\', \'%s\', \'NULL\', \'NULL\', \'%s\');'
% (str(i), '4', ('2009-' + str(random.randint(1, 12)) + '-'
+ str(random.randint(1, 28)) + ' 19:08:23')))
Tags: Internet | Programování | Python | Počítače | Databáze



Wiki2Tex - konverze Wiki syntaxe do LaTeXu psaná v Pythonu

Nov|25 2009

Od letošního roku jsem si zvykl používat DokuWiki pro editaci a správu různých dokumentů v psané podobě - technické zprávy, diplomová práce apod. Nejen že dokumenty jsou kdykoliv kdekoliv přístupné (DokuWiki nepoužívá ani databázi, stačí server s podporou PHP), ale udržují se informace o změnách a v případě chybné editace je možné starší verze dokumentů snadno dohledat. Takový primitivní Subversion, ovšem pro správu textů dostačující.

Nyní mě napadlo, že není složité převést syntaxi DokuWiki na syntaxi LaTeXu a tím pádem si ušetřit mnoho práce při odevzdávání. Bohužel jsem podobný program nenašel, tak jsem se pustil do jeho psaní. Vznikla aplikace Wiki2Tex v Pythonu 3 (bohužel není kompatibilní s verzemi 2.x), která pomocí regulárních výrazů převádí text v syntaxi Wiki do syntaxe LaTeXu. Převod je samozřejmě jen orientační a některé závěrečné úpravy musí být provedeny ručně, stejně jako definice dokumentu LaTeXu. Přesto doufám, že se bude hodit alespoň mě, v lepším případě i někomu jinému.

Aplikace Wifi2Tex.zip ke stažení.

Malá ukázka, jakým způsobem je převod implementován:


# images
inputStr = re.sub( r'\\\{\\\{.*:([^:]*)\|(.*)\\\}\\\}',
r'\\begin{figure}\n\centering\n\includegraphics[scale=1]{\1}'
+ r'\n\caption{\2}\n\end{figure}', inputStr)

# chapters and sections
chapters = [ #['chapter', '====='],
['section', '====='],
['subsection', '===='],
['subsubsection', '===']]

for i in range(len(chapters)):
inputStr = re.sub( chapters[i][1] + r'\s*([^=]*[^=\s]+)\s*' + chapters[i][1],
r'\\' + chapters[i][0] + r'{\1}', inputStr)

# bold and italic
inputStr = re.sub( r'\*\*([^\*]+)\*\*',
r'{\bf \1}', inputStr)
inputStr = re.sub( r'//([^/]+)//',
r'{\it \1}', inputStr)

Tags: Programování | Python | Počítače



Instalace mod_python 3.3.1

Aug|21 2008

Zase jsem se jednou potýkal s instalací apache&mysql + mod_python a zvláště s rozchozením toho posledního jsem měl jako obvykle problémy. Proto tu sepisuji postup, třeba to někomu pomůže. Pro informaci verze: Apache 2.2.8, mod_python 3.3.1, python 2.5.2.

Všechny balíčky jsem nainstaloval pomocí balíčkovače Synaptic pod oper. systémem Ubuntu 8.04 Hardy Heron a cílem bylo rozchodit modul Publisher.

Modul mod_python už byl aktivován (byl zkopírován ze složky /etc/apache/mods-avaible/ do /etc/apache/mods-enabled/. Podle návodu Testing mod_python jsem editoval soubor /etc/apache/apache2.conf, jenže tudy cesta nevedla. Místo toho je nutné editovat soubor /etc/apache/sites-enabled/000-default. Tam jsem pouze editoval řádek s AllowOverride, a po restartování apache (sudo /etc/init.d/apache2 restart) jsem mohl využít soubor .htaccess.

Do souboru /var/www/.htaccess jsem umístil potřebné řádky pro zpracování pythonovských skriptů:

AddHandler mod_python .py
PythonHandler mod_python.publisher
PythonDebug On

Potom jsem vytvořil jednoduchý skript test.py:

def index(req):
return "Hello world"

Ten jsem umístil do /var/www/ a od této doby jsem měl na adrese http://localhost/test.py můj vytoužený pozdrav.

Tags: Internet | Programování | Prohlížeče | Python | Sítě | Počítače



Hromadná změna kódování souborů v češtině

May| 8 2008

Pro hromadnou změnu kódování souborů existují některé prográmky. Mě se podařilo najít utilitku od Pavla Slezáka (http://www.slezak.name/pavel/kodovani.html), bohužel tento prográmek nepodporuje kódování UTF-8.

Skript v bashi

Hledal jsem dále. Na jiných stránkách (http://www.z-moravec.net/php_learn/hromadna-zmena-kodovani.php) je trochu jíný způsob - velmi jednoduchý kód pro bash.

for F in *.php
do
iconv -f windows-1250 -t utf-8 -o $F ${F}1
mv ${F}1 $F
done

Skript v Pythonu

Linux jsem ale zrovna nabootován neměl, tak jsem hledal dále. Již marně. Napadla mě ale jiná možnost - napsat si něco jednoduchého v Pythonu.

Níže je tedy uveden výsledek mého snažení, je to vcelku jednoduchý skript pro python (takže na počítači musí být nainstalován Python verze 2.4 a dále - http://www.python.org/). V budoucnu mu snad přibude nějaké GUI. Do té doby je to spíš taková inspirace.

import os

# seznam koncovek souboru, ktere maji byt prevedeny
extentions = ['php', 'html', 'htm']

# samotne prevedeni souboru
# @param string path soubor, ze ktereho se cte
# @param string path2 soubor, do ktereho je ukladano
def conv(path, path2):
f= open(path, 'rb')
content= unicode(f.read(), 'cp1250')
f.close()
f= open(path2, 'wb')
f.write(content.encode('utf-8'))
f.close()

# rekurzivne vola sama sebe od aktualniho adresare
# @param string path adresar, ktery je prohledavan
def chdir(path):
print '=======' + path + '======='
for fn in os.listdir(path):
if os.path.isfile(path + fn):
if fn.lower().split('.')[-1] in extentions:
print "converting... " + path + fn
conv(path + fn, path + fn)
elif os.path.isdir(path + fn):
chdir(path + fn + '/')

# inicializace pro aktualni adresar
chdir('')
Tags: Programování | Python | Počítače