<?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>SEO блог и уеб програмиране &#187; Уеб програмиране</title>
	<atom:link href="http://ganbox.com/blog/category/%d1%83%d0%b5%d0%b1-%d0%bf%d1%80%d0%be%d0%b3%d1%80%d0%b0%d0%bc%d0%b8%d1%80%d0%b0%d0%bd%d0%b5/feed/" rel="self" type="application/rss+xml" />
	<link>http://ganbox.com/blog</link>
	<description>SEO практика: трикове при оптимизация и решаване на проблеми при уеб програмиране.</description>
	<lastBuildDate>Tue, 07 Sep 2010 11:38:22 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
<xhtml:meta xmlns:xhtml="http://www.w3.org/1999/xhtml" name="robots" content="noindex" />
		<item>
		<title>Евтино решение за нов външен диск</title>
		<link>http://ganbox.com/blog/%d0%b5%d0%b2%d1%82%d0%b8%d0%bd%d0%be-%d1%80%d0%b5%d1%88%d0%b5%d0%bd%d0%b8%d0%b5-%d0%b7%d0%b0-%d0%bd%d0%be%d0%b2-%d0%b2%d1%8a%d0%bd%d1%88%d0%b5%d0%bd-%d0%b4%d0%b8%d1%81%d0%ba/</link>
		<comments>http://ganbox.com/blog/%d0%b5%d0%b2%d1%82%d0%b8%d0%bd%d0%be-%d1%80%d0%b5%d1%88%d0%b5%d0%bd%d0%b8%d0%b5-%d0%b7%d0%b0-%d0%bd%d0%be%d0%b2-%d0%b2%d1%8a%d0%bd%d1%88%d0%b5%d0%bd-%d0%b4%d0%b8%d1%81%d0%ba/#comments</comments>
		<pubDate>Sat, 07 Aug 2010 04:34:42 +0000</pubDate>
		<dc:creator>gan</dc:creator>
				<category><![CDATA[Уеб програмиране]]></category>
		<category><![CDATA[адаптер SATA USB]]></category>
		<category><![CDATA[архивиране]]></category>
		<category><![CDATA[външен диск]]></category>
		<category><![CDATA[твърд диск]]></category>
		<category><![CDATA[форматиране на диск]]></category>

		<guid isPermaLink="false">http://ganbox.com/blog/?p=962</guid>
		<description><![CDATA[Евтино решение за нов външен диск След като осъзнах, че имам нужда от поне 500 GB диск, на който да правя архив на по-важните си файлове, снимки и видео, започнах да търся какви дискове се предлагат. Отначало смятах да взема компактен външен диск, който да се захранва през USB порта. Предимството е, че лесно се [...]]]></description>
			<content:encoded><![CDATA[<h3>Евтино решение за нов външен диск</h3>
<h4><a href="http://ganbox.com/blog/wp-content/pub/adapter_USB_SATA_1.png" target="_blank"><img class="alignright size-medium wp-image-971" style="float:right" title="Адаптер USB SATA IDE комплект" src="http://ganbox.com/blog/wp-content/pub/adapter_USB_SATA_1-300x225.png" alt="Комплекта на преходник USB SATA IDE " height="180" /></a></h4>
<p>След като осъзнах, че имам нужда от поне 500 GB диск, на който да правя архив на по-важните си файлове, снимки и видео, започнах да търся какви дискове се предлагат. Отначало смятах да взема компактен външен диск, който да се захранва през USB порта. Предимството е, че лесно се пренася и нямаш нужда от допълнително захранване. Недостатък е, че бързо изхабява батерията на лаптопа. Най-евтините дискове с капацитет 500 GB бяха на цена от 170 лв нагоре в момента, в който пиша тази статия.</p>
<p>След това реших, че за архивиране на данни, не ми е нужна чак такава мобилност и започнах да търся нормален 3,5&#8220; твърд диск, който да може да се постави във външна кутия за диск и със собствено захранване. Оказа се, че тези кутии се намират трудно и цената им е незаслужено висока. И така почти случайно открих, че има и още един вариант, който е с около 50-60 лв по-евтин.</p>
<h4>Адаптер от SATA към USB<a href="http://ganbox.com/blog/wp-content/pub/adapter_USB_SATA_2.png" target="_blank"><img class="alignright size-medium wp-image-974" style="float: right;" title="Обикновен твърд диск, който не се монтира в кутия, а ползва адаптер USB/SATA" src="http://ganbox.com/blog/wp-content/pub/adapter_USB_SATA_2-300x225.png" alt="" width="300" height="225" /></a></h4>
<p>При използване на адаптер от SATA към USB, можеш да включиш обикновен твърд диск към USB порта без да го инсталираш в кутията на компютъра. Предимството е, че можеш сравнително лесно да включваш диска от един компютър на друг. В един момент, когато си позапълнил диска с данни и нямаш нужда да го разнасяш, можеш да си го инсталираш в кутията на компютъра. Единствения недостатък на адаптера е, че имаш няколко кабела в повече извън компютъра. С един кабел подобен на зарядно включваш диска към захранване 220 V, а с друг кабел, което е самия адаптер включваш диска към USB порта на компютъра. На първата снимка се вижда преходника от USB към SATA, всички кабели на снимката съм към комплекта и пристигат в кутията. Захранването отдясно е за диска заедно с късия четирижилен кабел с бял и черен накрайник. Останалите две части &#8211; черния и червения кабел са самия адаптер.</p>
<p>Скоростта на трансфер при прехвърляне на данни е над 12 MB в секунда при USB 2.0. Ако компютъра е стар и има само USB 1.1. порт, тогава скоростта е най-много 1.2 MB в секунда, но това е достатъчна скорост да пускаш филми с DVD качество директно от диска включен в USB порта. Към адаптера може да се включват и по-стари IDE дискове, но не съм го тествал още.</p>
<p>След като избрах този вариант започнах да правя проучване от кой онлайн магазин да си купя хард диск 500 GB и преходник от SATA към USB. Загубих час-два, докато накрая се спрях на два онлайн магазина, които предлагаха най-добра цена и най-добри условия по доставка, гаранция и обслужване.</p>
<p>От Euromall.bg избрах да купя следния <a title="Твърд диск 500 GB SATA" href="http://www.euromall.bg/components/hdd/HDD-SEAGATE-Barracuda-7200.12-ST3500418AS.html" target="_blank">500 GB твърд диск SATA интерфейс</a>.</p>
<p>Цена с доставка 99 лв. Гаранция 3 години. Поръчах го и платих при доставката. <a title="Лаптопи, компютри за дома и офиса." href="http://www.euromall.bg" target="_blank">Евромол</a> са сравнително нов онлайн магазин, който бързо се развива. Не бях пазарувал досега от тях, но съм доволен от цената и обслужването.</p>
<p>Адаптер (преходник) купих от друг онлайн магазин. Не бях купувал досега от там, но понеже цената не беше висока реших да тествам този магазин и дори предплатих с карта през epay.bg. Цена с доставка 26,26 лв.</p>
<p>Така за около 125 лв имам външен диск 500 GB, който работи чудесно. Много е тих и не загрява. Поставил съм го на бюрото отгоре. Кабелите съм ги скрил отзад зад бюрото, изглежда подобно на втората снимка. На третата снимка се вижда пълния комплект с включени всички кабели.</p>
<p>Голям плюс на избрания вариант е, че ти дава всички удобства на мобилен диск и освен това ти позволява, след като диска е почти пълен да го инсталираш в компютъра и да достъпваш данните с доста по-висока скорост.</p>
<p>Най-после се чувствам доста по-сигурен за данните си. <img src='http://ganbox.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<h3>Форматиране на нов твърд диск SATA под Линукс<a href="http://ganbox.com/blog/wp-content/pub/adapter_USB_SATA_3.png" target="_blank"><img class="alignright size-medium wp-image-977" style="float: right;" title="Пълен комплект адаптер и твърд диск ползван, като външен диск" src="http://ganbox.com/blog/wp-content/pub/adapter_USB_SATA_3-300x225.png" alt="" width="300" height="225" /></a></h3>
<p>(Ако твоята операционна система не е линукс базирана не е нужно да четеш нататък.)</p>
<p>Дискът е със SATA интерфейс, свързан към USB 1.1 порт, чрез адаптер. Операционната система е Fedora, но на почти всички линукси дистрибуции командите са тези. В моя случай имах само USB 1.1 и затова форматирането отне доста време.</p>
<p>Това което се въвежда от теб от клавиатурата е в <span style="color: #008000;">зелено</span>, това, което изписва компютъра е в <span style="color: #3366ff;">синьо</span>, моите коментари са в черно.</p>
<p>Основните команди са само три: <strong>fdisk</strong> &#8211; промяна на дяловете на диска, <strong>mkfs</strong> &#8211; форматиране и <strong>fsck &#8211; </strong> проверка за грешки, като се подават подходящите параметри.</p>
<p>Първо напиши</p>
<p>$ <span style="color: #008000;">dmesg</span></p>
<p>и в края на изведената информация ще видиш нещо като:</p>
<p><span style="color: #3366ff;">&#8230;</span></p>
<p><span style="color: #3366ff;">sd 26:0:0:0: [sdb] 976773168 512-byte hardware sectors (500108 MB)<br />
sd 26:0:0:0: [sdb] Write Protect is off<br />
sd 26:0:0:0: [sdb] Mode Sense: 28 00 00 00<br />
sd 26:0:0:0: [sdb] Assuming drive cache: write through</span></p>
<p>най-важната информация е sdb &#8211; това е името на диска, при теб може някоя от буквите да се различава. Ако това е така ще трябва да промениш буквите и в следващите команди.</p>
<p>$ <span style="color: #008000;">sudo fdisk /dev/sdb</span></p>
<p><span style="color: #3366ff;">[sudo] password for user:</span></p>
<p>въвеждаш паролата за текущия потребител user</p>
<p><span style="color: #3366ff;">Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel<br />
Building a new DOS disklabel with disk identifier 0x88c0fb67.<br />
Changes will remain in memory only, until you decide to write them.<br />
After that, of course, the previous content won&#8217;t be recoverable.</span></p>
<p><span style="color: #3366ff;">The number of cylinders for this disk is set to 60801.<br />
There is nothing wrong with that, but this is larger than 1024,<br />
and could in certain setups cause problems with:<br />
1) software that runs at boot time (e.g., old versions of LILO)<br />
2) booting and partitioning software from other OSs<br />
(e.g., DOS FDISK, OS/2 FDISK)<br />
Warning: invalid flag 0&#215;0000 of partition table 4 will be corrected by w(rite)</span></p>
<p><span style="color: #000080;">Command (m for help):</span> <span style="color: #008000;">p</span></p>
<p><span style="color: #3366ff;">Disk /dev/sdb: 500.1 GB, 500107862016 bytes<br />
255 heads, 63 sectors/track, 60801 cylinders<br />
Units = cylinders of 16065 * 512 = 8225280 bytes<br />
Disk identifier: 0x88c0fb67</span></p>
<p><span style="color: #3366ff;">Device Boot      Start         End      Blocks   Id  System</span></p>
<p>Ако размерът на диска не съответства, значи си объркал името на диска и трябва да прекратиш с команда <strong>q</strong>.</p>
<p><span style="color: #000080;">Command (m for help):</span> <span style="color: #008000;">n</span><br />
<span style="color: #000080;">Partition number (1-8):</span> <span style="color: #008000;">1</span></p>
<p>на следващите две стъпки просто натисни клавиша [Enter]</p>
<p><span style="color: #3366ff;"><span style="color: #000080;">First cylinder (0-60801):</span><br />
<span style="color: #000080;">Last cylinder or +size or +sizeM or +sizeK (0-60801, default 60801):</span></span><br />
<span style="color: #3366ff;">Using default value 60801</span></p>
<p><span style="color: #000080;">Command (m for help):</span> <span style="color: #008000;">p</span></p>
<p><span style="color: #3366ff;">Disk /dev/sdb (Sun disk label): 255 heads, 63 sectors, 60801 cylinders<br />
Units = cylinders of 16065 * 512 bytes</span></p>
<p><span style="color: #3366ff;">Device Flag    Start       End    Blocks   Id  System<br />
/dev/sdb1             0     60801 488384032+  83  Linux native</span></p>
<p>Ползвам цялото свободно място, защото ще ползвам диска само за данни.</p>
<p>До този момент всичко се случва само в паметта и ако прекъснеш с команда q нищо няма да се промени. При следващата команда <strong>w</strong> промените се записват на диска.</p>
<p><span style="color: #000080;">Command (m for help):</span> <span style="color: #008000;">w</span><br />
<span style="color: #3366ff;">The partition table has been altered!</span></p>
<p><span style="color: #3366ff;">Calling ioctl() to re-read partition table.<br />
Syncing disks.</span></p>
<p>Следващата команда отнема много време. Над 2 часа за 500 GB диск при USB 1.1.</p>
<p>$ <span style="color: #008000;">sudo mkfs -t ext3 /dev/sdb</span><br />
<span style="color: #3366ff;">mke2fs 1.41.4 (27-Jan-2009)<br />
/dev/sdb is entire device, not just one partition!<br />
Proceed anyway? (y,n) y<br />
Filesystem label=<br />
OS type: Linux<br />
Block size=4096 (log=2)<br />
Fragment size=4096 (log=2)<br />
30531584 inodes, 122096646 blocks<br />
6104832 blocks (5.00%) reserved for the super user<br />
First data block=0<br />
Maximum filesystem blocks=0<br />
3727 block groups<br />
32768 blocks per group, 32768 fragments per group<br />
8192 inodes per group<br />
Superblock backups stored on blocks:<br />
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,<br />
4096000, 7962624, 11239424, 20480000, 23887872, 71663616, 78675968,<br />
102400000</span></p>
<p><span style="color: #3366ff;">Writing inode tables: done<br />
Creating journal (32768 blocks): done</span></p>
<p>На следващата стъпка натисни клавиша [Enter] и пак трябва да почакаш около минута.</p>
<p><span style="color: #3366ff;">Writing superblocks and filesystem accounting information:<br />
done</span></p>
<p>This filesystem will be automatically checked every 26 mounts or<br />
180 days, whichever comes first.  Use tune2fs -c or -i to override.</p>
<p>Следващата команда също е много бавна за големи дискове.</p>
<p>$ <span style="color: #008000;">sudo fsck -f -y /dev/sdb</span><br />
<span style="color: #3366ff;">fsck 1.41.4 (27-Jan-2009)<br />
e2fsck 1.41.4 (27-Jan-2009)<br />
Pass 1: Checking inodes, blocks, and sizes</span></p>
<p>Тази стъпка отнема много време &#8211; над два часа и половина за 500 GB диск при USB 1.1.</p>
<p><span style="color: #3366ff;">Pass 2: Checking directory structure<br />
Pass 3: Checking directory connectivity<br />
Pass 4: Checking reference counts<br />
Pass 5: Checking group summary information</span></p>
<p>Тук чакаш още няколко минути.<br />
<span style="color: #3366ff;">/dev/sdb: 11/30531584 files (0.0% non-contiguous), 1966935/122096646 blocks</span></p>
<p>Готово. Може да тестваш с:</p>
<p>$ sudo mkdir /media/db</p>
<p>$ sudo mount /dev/sdb /media/db</p>
<p>$ df -h</p>
<p>трябва да ти покаже ред подобен на</p>
<p><span style="color: #3366ff;">/dev/sdb              459G  199M  435G   1% /media/db</span></p>
<p>Честито! Имаш още 500 GB място <img src='http://ganbox.com/blog/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p><span style="color: #3366ff;"><br />
</span></p>
<div style="float:right;display:block" class="counterViews">Брой разглеждания на тази статия: <b>529</b></div>]]></content:encoded>
			<wfw:commentRss>http://ganbox.com/blog/%d0%b5%d0%b2%d1%82%d0%b8%d0%bd%d0%be-%d1%80%d0%b5%d1%88%d0%b5%d0%bd%d0%b8%d0%b5-%d0%b7%d0%b0-%d0%bd%d0%be%d0%b2-%d0%b2%d1%8a%d0%bd%d1%88%d0%b5%d0%bd-%d0%b4%d0%b8%d1%81%d0%ba/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Блокиране на спам през cPanel</title>
		<link>http://ganbox.com/blog/%d0%b1%d0%bb%d0%be%d0%ba%d0%b8%d1%80%d0%b0%d0%bd%d0%b5-%d0%bd%d0%b0-%d1%81%d0%bf%d0%b0%d0%bc-%d0%bf%d1%80%d0%b5%d0%b7-cpanel/</link>
		<comments>http://ganbox.com/blog/%d0%b1%d0%bb%d0%be%d0%ba%d0%b8%d1%80%d0%b0%d0%bd%d0%b5-%d0%bd%d0%b0-%d1%81%d0%bf%d0%b0%d0%bc-%d0%bf%d1%80%d0%b5%d0%b7-cpanel/#comments</comments>
		<pubDate>Sat, 03 Jul 2010 19:36:15 +0000</pubDate>
		<dc:creator>gan</dc:creator>
				<category><![CDATA[Сигурност]]></category>
		<category><![CDATA[блокиране на спам]]></category>

		<guid isPermaLink="false">http://ganbox.com/blog/?p=954</guid>
		<description><![CDATA[Какво е СПАМ? За мен СПАМ е всяко едно неочаквано имейл съобщение, дори запитване дали може да ми пратят непоискано съобщение Напоследък върлува следния досаден СПАМ със заглавие: &#8222;Въпрос от Бизнес Каталог България&#8220; и текст: Уважаеми Дами и Господа, Бихме желали да поискаме разрешение да ви изпратим непоискано търговско съобщение. Темата му е &#8222;Каталог Медия [...]]]></description>
			<content:encoded><![CDATA[<h3>Какво е СПАМ?</h3>
<p>За мен СПАМ е всяко едно неочаквано имейл съобщение, дори запитване дали може да ми пратят непоискано съобщение <img src='http://ganbox.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Напоследък върлува следния досаден СПАМ със заглавие: &#8222;Въпрос от Бизнес Каталог България&#8220; и текст:</p>
<p><em>Уважаеми Дами и Господа,<br />
Бихме желали да поискаме разрешение да ви изпратим непоискано търговско съобщение.<br />
Темата му е &#8222;Каталог Медия и Реклама 2010&#8243;<br />
Ако искате да го прочетете, можете да посетите този линк &#8230;<br />
Ако не желаете да получавате повече полезна информация от нас, можете да запишете Вашият мейл тук &#8230;<br />
С уважение,<br />
Бизнес Каталог България<br />
02 421 40 44<br />
www.cаtаlogbg.biz</em></p>
<p><em>office@cаtаlogbg.biz</em></p>
<p><em>office@bаzi-dаnni.com</em></p>
<p>Това съобщение се получава по няколко пъти в една пощенска кутия. На пръв поглед това е съвсем културно съобщение, но искам да ти обърна внимание<em>,</em> че подобна опция при която се записваш, че не желаеш да получаваш имейли е много опасна! Това е сигурен начин да покажеш, че този имейл не само е валиден, а се преглежда редовно от човек. След като натрупат солидна база данни с примерно 20 000 имейла, тази компания може да реши тайно да продаде тази база с имейл адреси и тогава наистина ще започнеш да получаваш много съобщения. Подобен сценарий се случва всеки ден по света. Трябва добре да познаваш фирмата, която стои отсреща и да и имаш доверие. Например Google.</p>
<p>Ако искаш да спреш да получаваш подобни имейли във всичките мейл акаунти на твоя сайт и ако използваш хостинг с cPanel, може да направиш това, като блокираш този изпращач да не може да ти изпраща повече имейли. Това се прави лесно.</p>
<h3>Блокиране на СПАМ през cPanel</h3>
<p>Влез в cPanel контролния панел на твоя хостинг, в секцията Mail избери “Account Level Filtering”. Натисни бутона [Create a new Filter]. В първото поле <strong>Filter Name</strong>: въведи някакво име, което да те подсеща за какво е филтъра, например bazidanni. В полето под &#8222;Rules&#8220; в първия падащ списък остави избрано <strong>From</strong>, а във втория избери <strong>contains</strong> и в полето отдолу въведи <strong>bazi-danni.com</strong>. В падащия списък под <strong>Actions</strong> остави избрано <strong>Discard Message</strong>. Натисни бутона [Activate] и ще имаш филтър, който ще унищожава всички имейл съобщения, които съдържат в хедъра си From низа bazi-danni.com. От този момент няма да получаваш повече писма, от пощенски кутии, които завършват на @bazi-danni.com.</p>
<p>По подобен начин може да зададеш друг филтър, като например вместо From избереш Subject и като текст въведеш Viagra. По този начин ще бъдат изтривани автоматично писма с оферти за виагра.</p>
<p>Темата е доста обширна и тук е даден само бърз пример</p>
<div style="float:right;display:block" class="counterViews">Брой разглеждания на тази статия: <b>617</b></div>]]></content:encoded>
			<wfw:commentRss>http://ganbox.com/blog/%d0%b1%d0%bb%d0%be%d0%ba%d0%b8%d1%80%d0%b0%d0%bd%d0%b5-%d0%bd%d0%b0-%d1%81%d0%bf%d0%b0%d0%bc-%d0%bf%d1%80%d0%b5%d0%b7-cpanel/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Оптимизиране на SQL заявки</title>
		<link>http://ganbox.com/blog/%d0%be%d0%bf%d1%82%d0%b8%d0%bc%d0%b8%d0%b7%d0%b8%d1%80%d0%b0%d0%bd%d0%b5-%d0%bd%d0%b0-sql-%d0%b7%d0%b0%d1%8f%d0%b2%d0%ba%d0%b8/</link>
		<comments>http://ganbox.com/blog/%d0%be%d0%bf%d1%82%d0%b8%d0%bc%d0%b8%d0%b7%d0%b8%d1%80%d0%b0%d0%bd%d0%b5-%d0%bd%d0%b0-sql-%d0%b7%d0%b0%d1%8f%d0%b2%d0%ba%d0%b8/#comments</comments>
		<pubDate>Fri, 09 Apr 2010 09:48:41 +0000</pubDate>
		<dc:creator>gan</dc:creator>
				<category><![CDATA[Уеб програмиране]]></category>
		<category><![CDATA[mySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[SQL заявки]]></category>
		<category><![CDATA[бавни SQL заявки]]></category>
		<category><![CDATA[бързодействие]]></category>
		<category><![CDATA[оптимизация]]></category>
		<category><![CDATA[оптимизация на SQL]]></category>
		<category><![CDATA[оптимизиране]]></category>
		<category><![CDATA[оптимизиране на SQL]]></category>
		<category><![CDATA[урок]]></category>

		<guid isPermaLink="false">http://ganbox.com/blog/?p=848</guid>
		<description><![CDATA[Основни положения при оптимизация на mySQL Обикновено проблемите с бавни SQL заявки се дължат на грешно проектирана база данни, липса или грешно използване на индекси и най-често неправилно написани SQL заявки. Статията разглежда няколко примера от практиката, които дават идеи за нов начин на писане на оптимизирани SQL заявки, при който не се прехвърлят много [...]]]></description>
			<content:encoded><![CDATA[<h2>Основни положения при оптимизация на mySQL</h2>
<p>Обикновено проблемите с <strong>бавни SQL заявки</strong> се дължат на грешно проектирана база данни, липса или грешно използване на индекси и най-често неправилно написани SQL заявки.</p>
<p>Статията разглежда няколко примера от практиката, които дават идеи за нов начин на писане на <strong>оптимизирани SQL заявки</strong>, при който не се прехвърлят много данни, за да се увеличи бързодействието.</p>
<h3>Мониторинг на SQL заявки</h3>
<p>На първо място препоръчвам на всеки използващ mySQL да ползва лог на бавните заявки. Активира се лесно и записва всяка заявка, която отнеме за изпълнението си повече от предварително зададено време (обикновено 10 сек.). Все пак не може да решиш проблем, ако не знаеш, че съществува <img src='http://ganbox.com/blog/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /><br />
Използвай EXPLAIN пред SELECT за информация относно заявката &#8211; кой индекс се използва, колко реда се преглеждат и др.<br />
За мониторинг в реално време препоръчвам mytop &#8211; приложение написано на Perl, което показва всички активни заявки и колко време отнемат.</p>
<h3>Няколко бързи съвета за начинаещи</h3>
<p>1. Ползвай колона id с атрибути PRIMARY и auto_increment за всяка таблица, дори да ти се струва, че никога няма да ти трябва.<br />
2. Избягвай винаги &#8222;SELECT * FROM &#8230;&#8220; вместо това пиши &#8222;SELECT col1, col2, col3&#8230; FROM &#8230;&#8220; &#8211; изброявай нужните колони вместо да вземаш всички данни.<br />
3. Никога не ползвай &#8222;SELECT (*) FROM &#8230;&#8220;, а пиши &#8222;SELECT (id) FROM &#8230;&#8220;, където id е колона с уникални стойности.<br />
4. При създаването на таблицата създай индекси по всяка една колона, по която в бъдеще се очаква да сортираш данните или да извличаш данни като търсиш по стойност в тази колона.<br />
5. Почти винаги т.4 е недостатъчна &#8211; трудно е да създадеш всички необходими индекси предварително. При написването на всяка нова заявка проверявай какви са колоните, по които се търси и провери дали има индекси по тях &#8211; ако няма ги създай веднага!<br />
6. Ползвай сложни индекси. Ако имаш заявка, в която се търси по повече от една колона например съдържа &#8222;&#8230; WHERE user_id = 8 AND date > &#8217;2010-01-01&#8242; &#8222;, в този случай ако имаш отделни индекси по user_id и по date ще бъде автоматично избран и ползван само единия. Ако много често се изпълнява такава заявка (или си я открил в лога с бавни заявки) ти трябва сложен индекс по двете колони. Очаквай отделна статия по въпроса за комбинираните индекси.<br />
7. Нормализиране на таблици. Тук няма да влизам в детайли, а само ще спомена, че ако в някоя колона имаш данни, които изглеждат като: &#8222;4,5,13,45,345&#8243; &#8211; няколко стойности разделени със запетая, това почти винаги е знак за грешно проектирана база данни.<br />
8. Когато свързваш две таблици трябва типа на колоните, по които се свързва да съвпада точно, например ако едната е от тип INT(8), а другата е от тип INT(11) може да се очакват проблеми.</p>
<h3>Аксиома на gan за оптимизация на SQL</h3>
<p>Стреми се да пишеш SQL заявките си така, все едно уеб сървъра и SQL сървъра са на различни машини &#8211; пренесените данни между двата трябва да са минимални!</p>
<h2>Откриване на позицията на ред след сортиране на таблица</h2>
<p>Нека да предположим, че имаме сайт за игра и има таблица за класиране UserTop с колони username и points, в която за всеки потребител се записва, колко точки е спечелил общо от всички игри. Колоната username съдържа уникални стойности. Пример за SQL таблица UserTop:</p>
<table>
<tbody>
<tr>
<th>username</th>
<th>points</th>
</tr>
<tr>
<td>someuser</td>
<td>150</td>
</tr>
<tr>
<td>otheruser</td>
<td>50</td>
</tr>
<tr>
<td>ganbox</td>
<td>250</td>
</tr>
<tr>
<td>randomuser</td>
<td>350</td>
</tr>
<tr>
<td>vox</td>
<td>250</td>
</tr>
</tbody>
</table>
<p>След приключване на всяка игра по потребителско име се намира реда за играча и точките му се увеличават с тези от последната игра. Нека да кажем, че в момента е логнат потребител ganbox и искаме да покажем на играча на коя позиция е в класацията. Затова трябва да сортираме таблицата по колона points в намаляващ ред и да видим на коя позиция се намира ganbox. Един начинаещ програмист ще направи следното:</p>
<p><span style="color: #800000;">Грешно решение:</span></p>
<div class="codecolorer-container php default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000088;">$query</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;SELECT * FROM UserTop ORDER BY points DESC &quot;</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$results</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">GetAll</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$query</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;"># всички резултати в масив (ползва се ADODB библиотека за краткост)<br />
</span><span style="color: #000088;">$pos</span><span style="color: #339933;">=</span><span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span><br />
<span style="color: #b1b100;">for</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$i</span><span style="color: #339933;">=</span><span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span> <span style="color: #000088;">$i</span><span style="color: #339933;">&lt;</span>count<span style="color: #009900;">&#40;</span><span style="color: #000088;">$results</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000088;">$i</span><span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span> <br />
&nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$result</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$i</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'username'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">==</span> <span style="color: #0000ff;">'ganbox'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$pos</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$i</span><span style="color: #339933;">+</span><span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>Тук има няколко грешки:<br />
1. Взема се цялото съдържание на таблица UserTop &#8211; може да бъде огромно количество данни.<br />
2. На всяка итерация на цикъла for се оценява големината на масива $results.<br />
3. След като е намерена и записана позицията в pos, цикъла не се прекъсва, а продължава да се върти безсмислено.<br />
Не можете да си представите, колко много хора пишат по този небрежен начин. Затова много сайтове за игри работят отчайващо бавно при използване от много хора.</p>
<p>Следва малко по-добро, но все още неправилно решение.<br />
<span style="color: #800000;">Друго грешно решение:</span></p>
<div class="codecolorer-container php default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000088;">$query</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;SELECT username FROM UserTop ORDER BY points DESC &quot;</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$results</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">GetAll</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$query</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;"># всички резултати в масив<br />
</span><span style="color: #000088;">$pos</span><span style="color: #339933;">=</span><span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$size</span><span style="color: #339933;">=</span><a href="http://www.php.net/count"><span style="color: #990000;">count</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$results</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #b1b100;">for</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$i</span><span style="color: #339933;">=</span><span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span> <span style="color: #000088;">$i</span><span style="color: #339933;">&lt;</span><span style="color: #000088;">$size</span><span style="color: #339933;">;</span> <span style="color: #000088;">$i</span><span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$result</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$i</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'username'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">==</span> <span style="color: #0000ff;">'ganbox'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$pos</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$i</span><span style="color: #339933;">+</span><span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">break</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>Подобренията се виждат:<br />
1. Избират се само данните от колона username &#8211; все още връща всички редове и данните са прекалено много.<br />
2. Оценката на големината на масива е изнесена извън цикъла.<br />
3. След откриване на позицията цикъла спира.<br />
По точки 2. и 3. сме ОК, но т. 1 е голям проблем. Представи си, че уеб сървъра и SQL сървъра са на отделни машини &#8211; всички данни от колона username трябва да минат по мрежата, ако таблицата съдържа много редове и се ползва от много хора, това ще доведе до значително забавяне. Така стигаме до идеята, че тази задача трябва да се <strong>оптимизира</strong>, като обработката се изнесе към SQL сървъра.</p>
<p>Почти правилно решение:</p>
<div class="codecolorer-container php default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000088;">$query</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;SELECT COUNT( username ) AS pos FROM UserTop WHERE points &gt;= (SELECT points FROM UserTop WHERE username='ganbox' ) &quot;</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$pos</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">GetOne</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$query</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;"># един резултат</span></div></div>
<p>Първо се изпълнява заявката в скобите, която връща точките на текущия играч (низа &#8216;ganbox&#8217; трябва да се замести с потребителското име на логнатия играч). След това се вземат всички редове, които имат повече точки (включително тези които имат равен брой точки с играча) и се преброяват. Връща се едно единствено число &#8211; прекрасно!<br />
Има един малък проблем. Ако има играчи с брой точки равен на броя точки на текущия адрес, позицията няма да е вярна. Затова:</p>
<p><span style="color: #008000;">Правилно решение:</span></p>
<div class="codecolorer-container php default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000088;">$query</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;SELECT COUNT( username ) AS pos FROM UserTop WHERE points &gt; (SELECT points FROM UserTop WHERE username='ganbox' ) &quot;</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$pos</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">GetOne</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$query</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;"># един резултат<br />
</span><span style="color: #000088;">$pos</span><span style="color: #339933;">++;</span> <span style="color: #666666; font-style: italic;"># това е търсената позиция</span></div></div>
<p>Знакът е > защото в класация сортираме от по-голямо към по-малко.</p>
<p>.</p>
<p>Ако ти е станало интересно продължавай да четеш, ще усложним задачите с примери от практиката.<br />
Нека освен таблица UserTop, която е класация имаме UserLog, в която в края на всяка игра се прави запис, като се записва време на приключване на играта и кой потребител колко точки е спечелил през последната игра:</p>
<table>
<tbody>
<tr>
<th>timestamp</th>
<th>username</th>
<th>poits</th>
</tr>
<tr>
<td>2010-01-10 11:12:23</td>
<td>someuser</td>
<td>100</td>
</tr>
<tr>
<td>2010-01-11 10:24:33</td>
<td>otheruser</td>
<td>20</td>
</tr>
<tr>
<td>2010-01-12 15:14:13</td>
<td>ganbox</td>
<td>60</td>
</tr>
<tr>
<td>2010-01-15 19:15:55</td>
<td>randomuser</td>
<td>90</td>
</tr>
<tr>
<td>2010-02-15 11:52:54</td>
<td>vox</td>
<td>80</td>
</tr>
<tr>
<td>2010-04-08 22:04:44</td>
<td>someuser</td>
<td>50</td>
</tr>
<tr>
<td>2010-04-08 22:05:07</td>
<td>otheruser</td>
<td>30</td>
</tr>
<tr>
<td>2010-04-08 22:05:34</td>
<td>ganbox</td>
<td>190</td>
</tr>
<tr>
<td>2010-04-08 22:06:17</td>
<td>randomuser</td>
<td>260</td>
</tr>
<tr>
<td>2010-04-08 22:06:51</td>
<td>vox</td>
<td>140</td>
</tr>
<tr>
<td>2010-04-08 22:07:58</td>
<td>vox</td>
<td>30</td>
</tr>
</tbody>
</table>
<p>Задачата е да подредим потребителите в класацията UserTop така, че ако няколко души имат равен брой точки по-напред да излиза този, който е играл по-скоро. В примера vox и ganbox имат еднакъв брой 250 точки, но vox трябва да излиза по-напред, защото е играл последен.</p>
<h3>Сортиране на данни по два критерия в различни таблици</h3>
<p>Заявката, която ще изведе играчите сортирани първо по брой точки, а тези с еднакъв брой по времето на последната активност:</p>
<div class="codecolorer-container php default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000088;">$query</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;SELECT T.username, T.points FROM UserTop T LEFT JOIN UserLog L USING(username) GROUP BY username ORDER BY T.points DESC , L.timestamp DESC&quot;</span><span style="color: #339933;">;</span></div></div>
<p>Дотук добре. Сега освен страницата с тази класация искаме да показваме последните 10 действия &#8211; последните 10 играчи, които са играли. Там разбира се може да има повторения. Заявката е елементарна, но ни подготвя за следващата задача.</p>
<div class="codecolorer-container php default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000088;">$query</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;SELECT username, points FROM `UserLog` ORDER BY `UserLog`.`timestamp` &nbsp;DESC LIMIT 10&quot;</span><span style="color: #339933;">;</span></div></div>
<p>Забеляза ли, че не ползвам &#8222;SELECT * FROM&#8220;, а избирам тези които ми трябват (не го забравяй!).</p>
<p>Добре стигнахме до интересното. Следват два примера от практиката.</p>
<h4>Откриване на класирането на играч в края на игра</h4>
<p>Искаме в края на всяка игра освен да добавим запис в UserLog и да увеличим точките на играча в UserTop, да намерим новата позиция на играча в класацията и общия брой на точките му, за да може да му съобщим тези данни.</p>
<p><span style="color: #008000;">Правилно решение:</span></p>
<div class="codecolorer-container php default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000088;">$query</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot; SET @num:=0; SELECT username, pos, points FROM (SELECT @num := @num + 1 AS pos, T.points, T.username FROM UserTop T LEFT JOIN UserLog L USING(username) GROUP BY T.username ORDER BY T.points DESC, L.timestamp DESC) as R WHERE username = 'ganbox' &quot;</span><span style="color: #339933;">;</span></div></div>
<p>Вижда се, че ganbox е на 3-то място с 250 точки, а vox на второ пак с 250, но е играл по-скоро.<br />
Заявката отново е <strong>супер оптимизирана</strong> <em>според аксиомата на gan</em> <img src='http://ganbox.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  така, че да върне само нужните данни.<br />
Използва вътрешна SQL променлива @num, която първоначално се нулира. След това се изпълнява вътрешната заявка, която написана отделно:</p>
<div class="codecolorer-container php default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000088;">$query</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot; SET @num := 0; SELECT @num := @num + 1 AS pos, T.points, T.username FROM UserTop T LEFT JOIN UserLog L USING(username) GROUP BY T.username ORDER BY T.points DESC, L.timestamp DESC&quot;</span> <span style="color: #339933;">;</span></div></div>
<p>ще върне всички играчи в класацията с добавена колона с име pos, в която е позицията на всеки играч. По този начин външната заявка има задачата само да филтрира данните за играча, който ни интересува.</p>
<h4>Откриване на запис отпаднал от последните 10 действия</h4>
<p>Искаме още в края на всяка игра, да намерим кой играч е отпаднал на 11-място в лога (т.е. името му не се вижда вече в последните 10) и само ако името му го няма в първите 10 резултата да предприемем действие &#8211; например да го поканим да играе отново.</p>
<p>Как да решим тази задача? Можем лесно да вземем играча на позиция 11, както и да изведем всички от първите 10 позиции, но как да проверим дали този от 11-та се съдържа в първите 10?<br />
Единия подход е с една заявка да вземем играча X от 11 позиция. След това с втора заявка да вземем потребителските имена на всички от първите 10, да ги заредим в PHP масив и да потърсим X в масива. Както вече се досети този подход не ми харесва, защото за 10 не е страшно, но ако са 100, а ако са 1000? Трябва ни отново <strong>оптимизирано решение</strong> с минимално прехвърляне на данни.</p>
<p><span style="color: #008000;">Правилно решение:</span></p>
<div class="codecolorer-container php default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000088;">$query</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;SET @L:=(SELECT username FROM UserLog ORDER BY timestamp DESC LIMIT 10,1); SELECT @L AS username,SUM(F) AS cnt FROM (SELECT IF(username=@L,1,0) AS F FROM UserLog ORDER BY timestamp DESC LIMIT 0,10) AS T&quot;</span><span style="color: #339933;">;</span></div></div>
<p>Тази заявка ще върне резултат:</p>
<div class="codecolorer-container php default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><a href="http://www.php.net/array"><span style="color: #990000;">Array</span></a><br />
<span style="color: #009900;">&#40;</span><br />
<span style="color: #009900;">&#91;</span>username<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'someuser'</span><span style="color: #339933;">,</span><br />
<span style="color: #009900;">&#91;</span>cnt<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=&gt;</span> &nbsp; &nbsp;1<br />
<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<p>Наистина ако сортираш UserLog от примера по време в обратен ред, someuser е на 11 позиция. Също така се среща на 6-та позиция и затова cnt е 1, като cnt показва не само дали се среща, но и колко пъти се среща в позициите от 1 до 10. По този начин предприемаш действие само ако cnt=0.</p>
<p>Това бяха само някои идеи за нов стил на писане на SQL заявки с цел <strong>оптимизиране на бързодействието</strong>. За пълнота ще спомена, че в много случаи отлични резултати могат да се постигнат при използване на <strong>кеширане на SQL заявки</strong>. Самото кеширане на заявки се програмира лесно. Трудното е да се определи в кой момент да се ползва кеш. Темата ще бъде разгледана в друга статия.</p>
<p>Всички SQL заявки са тествани и работят. Ще се радвам на коментари по темата.</p>
<div style="float:right;display:block" class="counterViews">Брой разглеждания на тази статия: <b>1873</b></div>]]></content:encoded>
			<wfw:commentRss>http://ganbox.com/blog/%d0%be%d0%bf%d1%82%d0%b8%d0%bc%d0%b8%d0%b7%d0%b8%d1%80%d0%b0%d0%bd%d0%b5-%d0%bd%d0%b0-sql-%d0%b7%d0%b0%d1%8f%d0%b2%d0%ba%d0%b8/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Бутончета за споделяне на линкове v.3</title>
		<link>http://ganbox.com/blog/sb3/</link>
		<comments>http://ganbox.com/blog/sb3/#comments</comments>
		<pubDate>Sun, 04 Apr 2010 22:13:01 +0000</pubDate>
		<dc:creator>gan</dc:creator>
				<category><![CDATA[SEO инструменти]]></category>
		<category><![CDATA[Софтуер]]></category>
		<category><![CDATA[безплатен]]></category>
		<category><![CDATA[бутони]]></category>
		<category><![CDATA[връзки]]></category>
		<category><![CDATA[линкове]]></category>
		<category><![CDATA[плъгин]]></category>
		<category><![CDATA[скрипт]]></category>
		<category><![CDATA[споделяне]]></category>

		<guid isPermaLink="false">http://ganbox.com/blog/?p=836</guid>
		<description><![CDATA[Тази статия е продължение на статиите Безплатен скрипт за бутони към социални мрежи и  Бутони за социални мрежи v.2 в които се представя безплатен JavaScript за създаване на бутончета за споделяне на линкове. Също така и продължение на статията WordPress плъгин за социални мрежи която представя безплатен WordPress плъгин базиран на плъгина Sociable, но специално [...]]]></description>
			<content:encoded><![CDATA[<p>Тази статия е продължение на статиите <a href="/blog/sb/" target="_blank">Безплатен скрипт за бутони към социални мрежи</a> и  <a href="/blog/sb2/" target="_blank">Бутони за социални мрежи v.2 </a>в които се представя безплатен JavaScript за създаване на бутончета за споделяне на линкове. Също така и продължение на статията <a href="/blog/плъгин-за-социални-мрежи/" target="_blank">WordPress плъгин за социални мрежи </a>която представя безплатен WordPress плъгин базиран на плъгина Sociable, но специално преработен за български сайтове, които дават реален линк и са максимално <a href="/seo" target="_blank">SEO</a> ефективни.</p>
<p>И двата скрипта генерират аналогични бутони, които са най-адекватни към момента.</p>
<p>В новата трета версия са добавени бутони за Google Buzz, cenbg.com и uhaaa.net.</p>
<h3>JavaScript плъгин за споделяне на линкове</h3>
<h4>Енкодинг UTF-8</h4>
<p>Постави в  твоя сайт HTML кода:</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #339933;">&lt;!--</span> Start ganbox.<span style="color: #660066;">com</span> code v.3 <span style="color: #339933;">--&gt;&lt;</span>script src<span style="color: #339933;">=</span><span style="color: #3366CC;">&quot;http://ganbox.com/inc/sb3.js&quot;</span> type<span style="color: #339933;">=</span><span style="color: #3366CC;">&quot;text/javascript&quot;</span><span style="color: #339933;">&gt;&lt;/</span>script<span style="color: #339933;">&gt;&lt;!--</span> End ganbox.<span style="color: #660066;">com</span> code <span style="color: #339933;">--&gt;</span></div></div>
<h4>Енкодинг CP1251</h4>
<p>Ако твоя сайт е с кодиране на текста cp1251, тогава използвай следната версия на скрипта:</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp;<span style="color: #339933;">&lt;!--</span> Start ganbox.<span style="color: #660066;">com</span> Social Bookmark code v.3 <span style="color: #339933;">--&gt;&lt;</span>script src<span style="color: #339933;">=</span><span style="color: #3366CC;">&quot;http://ganbox.com/inc/sb3cp1251.js&quot;</span> type<span style="color: #339933;">=</span><span style="color: #3366CC;">&quot;text/javascript&quot;</span><span style="color: #339933;">&gt;&lt;/</span>script<span style="color: #339933;">&gt;&lt;!--</span> End ganbox.<span style="color: #660066;">com</span> code <span style="color: #339933;">--&gt;</span></div></div>
<p>Работещ пример има в сайта <a href="http://rechnik.info/" target="_blank">Речник на думите в българския език</a></p>
<h3>WordPress плъгин за бутони за социални мрежи</h3>
<p>Новата версия може да изтеглиш от връзката <a href="http://ganbox.com/blog/wp-content/pub/ganbox.com_sociable.zip">ganbox.com_sociable</a></p>
<p>Работеща версия има в този блог и бутоните се виждат в края на статията.</p>
<p>1. Ако вече ползваш стара версия на Sociable, за да инсталираш тази версия първо изключи стария плъгин.</p>
<p>2. Изтрий папката на старата версия от директория /wp-content/plugins на твоя сървър.</p>
<p>3. Разархивирай zip файла и качи папката sociable в /wp-content/plugins</p>
<p>4. Включи плъгина от списъка с Разширения в админ панела.</p>
<p>5. Влез в Настройки / Sociable и натисни бутона [Стандартни настройки подходящи за български сайтове].</p>
<p>Ако досега никога не си ползвал Sociable, за да го направиш изпълни само т.3 и т.4. Използването на този плъгин може да ти донесе линкове към вътрешни страници на твоя сайт и ще има добър SEO ефект.</p>
<div style="float:right;display:block" class="counterViews">Брой разглеждания на тази статия: <b>1189</b></div>]]></content:encoded>
			<wfw:commentRss>http://ganbox.com/blog/sb3/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Зареждане на данни с Ajax от отдалечен сървър</title>
		<link>http://ganbox.com/blog/%d0%b7%d0%b0%d1%80%d0%b5%d0%b6%d0%b4%d0%b0%d0%bd%d0%b5-%d0%bd%d0%b0-%d0%b4%d0%b0%d0%bd%d0%bd%d0%b8-%d1%81-ajax-%d0%be%d1%82-%d0%be%d1%82%d0%b4%d0%b0%d0%bb%d0%b5%d1%87%d0%b5%d0%bd-%d1%81%d1%8a%d1%80/</link>
		<comments>http://ganbox.com/blog/%d0%b7%d0%b0%d1%80%d0%b5%d0%b6%d0%b4%d0%b0%d0%bd%d0%b5-%d0%bd%d0%b0-%d0%b4%d0%b0%d0%bd%d0%bd%d0%b8-%d1%81-ajax-%d0%be%d1%82-%d0%be%d1%82%d0%b4%d0%b0%d0%bb%d0%b5%d1%87%d0%b5%d0%bd-%d1%81%d1%8a%d1%80/#comments</comments>
		<pubDate>Mon, 15 Mar 2010 09:48:49 +0000</pubDate>
		<dc:creator>gan</dc:creator>
				<category><![CDATA[Уеб програмиране]]></category>
		<category><![CDATA[Ajax]]></category>
		<category><![CDATA[бързодействие]]></category>
		<category><![CDATA[оптимизация]]></category>
		<category><![CDATA[оптимизиране]]></category>
		<category><![CDATA[сигурност]]></category>
		<category><![CDATA[съвет]]></category>
		<category><![CDATA[урок]]></category>

		<guid isPermaLink="false">http://ganbox.com/blog/?p=737</guid>
		<description><![CDATA[Задача за оптимизиране бързината на сайт Наскоро работих по сайта Речник на думите в българския език. В този сайт при търсене по някоя дума в дясната колона се зарежда блок с подобни думи. Подобните думи са такива, които се получават от търсената дума с добавяне, премахване или подмяна на една или две букви. За откриването [...]]]></description>
			<content:encoded><![CDATA[<h3>Задача за оптимизиране бързината на сайт</h3>
<p>Наскоро работих по сайта <a href="http://rechnik.info/">Речник на думите в българския език. </a>В този сайт при търсене по някоя дума в дясната колона се зарежда блок с подобни думи. Подобните думи са такива, които се получават от търсената дума с добавяне, премахване или подмяна на една или две букви. За откриването на такива думи се използва алгоритъм с висока степен на сложност, който е бавен, защото претърсва цялата таблица с думи. Таблицата беше с размер около 100 000 реда и нарастваше и в резултат на това зареждането на страницата се бавеше до към 30 секунди &#8211; прекалено дълго време за уеб страница. Задачата ми беше да измисля начин за <a href="http://ganbox.com/seo-uslugi#оптимизиране-бързодействие">оптимизиране на бързодействието на сайта</a>.</p>
<h3>Решение</h3>
<p>Първото, което направих е да опитам да оптимизирам SQL заявката. Ползваният алгоритъм не подлежи на <strong>оптимизация</strong>, затова се наложи да прибягна до някои дребни хитрости. Например търсене на подобни думи в ограничен набор от думи с дължина +/-2 спрямо дължината на търсената дума. Създадох някои допълнителни индекси на SQL таблиците и успях да съкратя средното време на около 8 секунди. Да чакаш цялата страница 8 секунди също е прекалено досадно и затова направих блока с подобни думи да се зарежда с Ajax. По този начин страницата се показваше веднага и само блока се бавеше, което беше напълно допустимо. Вече си мислех, че съм приключил, когато дойде писмо от хостинг доставчика, че се ползва прекалено бавна заявка, която бави другите сайтове на този споделен хостинг и настояваха да се <strong>оптимизира</strong>. Така стигнах до идеята, че данните за подобните думи трябва да се зареждат от отдалечен сървър. За да стане възможно това, трябва отдалеченият сървър да има същата таблица с думи в базата си данни. Направих автоматичен скрипт, който периодично да копира таблиците от единия сървър на другия. По този начин освен всичко друго се получи и още един архив на данните. След това оставаше да направя Ajax да се обръща към новия сървър. Тук отново има проблем: от съображения за сигурност Ajax не може да се обръща към домейн различен от този, на който се изпълнява. За да заобиколя това ограничение аз използвам следната програмистка техника: Ajax се обръща към скрипта similarClient.php разположен локално на сървъра на rechnik.info, който прави заявка към скрипт с име words.php на отдалечения сървър. Там се търси за подобни думи в копието на базата данни и намерения резултат се изпраща към similarClient.php, който го връща като резултат към Ajax. Към цялата система се добавя и кеширане на заявките, локално върху отдалечения сървър &#8211; този подход спестява дисково пространство на хостинга за сметка на увеличен трафик. При първото търсене в речника по дадена дума резултата се бави няколко секунди, но при всяко следващо търсене по тази дума, резултата се взема от кеш и става почти моментално. Всичко това може да изглежда малко сложно, но можеш да видиш колко добре действа в сайта на <a href="http://rechnik.info">Речника</a>.</p>
<h3>Сигурност</h3>
<p>Скриптът разположен на отдалечения сървър, който получава дума и връща списък с подобни думи е уеб скрипт и се извиква през HTTP. Това означава, че всеки който знае URL адреса и какви параметри приема, може лесно да използва това за свои цели и да прави заявки към сървъра. Използвайки горния метод, аз скривам URL адреса и това повишава сигурността многократно. Въпреки това е възможно връзката да бъде подслушана или логовете на сървъра да станат достъпни публично. Това ще разкрие URL адреса и някой може да се възползва. Затова един съвет: никога не разчитай само на сложен и таен URL адрес на скрипт!</p>
<p>Аз използвам допълнителни механизми за защита: отдалеченият сървър приема заявки само от IP адреса на rechnik.info. Това увеличава сигурността, но за съжаление не е напълно достатъчно, защото е възможно да пристигнат заявки с фалшифициран IP адрес. Следващиата стъпка е добавяне на кодиран параметър в GET заявката. По този начин URL адреса на заявката прилича на следния:</p>
<pre>http://remote.domain.com/words.php?a=дума&amp;code=a4b25d814f32b2c852c3d71d3</pre>
<p>Низа подаван в променливата &#8222;code&#8220;, е кодирана от скрипта similarClient.php и само скрипта words.php знае как да го разкодира и да разбере дали е валиден. Резултат се връща, само ако стойността е валидна, в противен случай опита се записва и се съобщава на админ. За да може някой да хакне това, трябва да има FTP достъп до някой от двата php файла.Следващата стъпка е ползване на HTTPS вместо HTTP, но тук вече навлизаме в сферата на банковия софтуер <img src='http://ganbox.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Сигурен съм, че много хора ще се запитат: &#8222;За какво е всичко това? Какво толкова защитаваш?&#8220;.</p>
<p>Нека да кажем, че се упражнявам <img src='http://ganbox.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  Не обичам да оставям нещата на случайността и не правя компромиси със сигурността. Винаги изпипвам нещата и се подсигурявам двойно. Препоръчвам ти да се научиш да работиш по този начин.</p>
<h3>SEO</h3>
<p>Описаната система си има и недостатъци. От <a href="http://ganbox.com/seo">SEO</a> гледна точка връзките в блока Подобни думи са невидими за търсачките. За да може сайта да се индексира добре е нужен или Google sitemap, или допълнителен блок с връзки като този със &#8222;Случайни думи&#8220;. Още по-добра работа би свършил блок със &#8222;Съседни думи&#8220;, в който за дадена страница връзките винаги да са едни и същи.</p>
<div style="float:right;display:block" class="counterViews">Брой разглеждания на тази статия: <b>1458</b></div>]]></content:encoded>
			<wfw:commentRss>http://ganbox.com/blog/%d0%b7%d0%b0%d1%80%d0%b5%d0%b6%d0%b4%d0%b0%d0%bd%d0%b5-%d0%bd%d0%b0-%d0%b4%d0%b0%d0%bd%d0%bd%d0%b8-%d1%81-ajax-%d0%be%d1%82-%d0%be%d1%82%d0%b4%d0%b0%d0%bb%d0%b5%d1%87%d0%b5%d0%bd-%d1%81%d1%8a%d1%80/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
	</channel>
</rss>
