Arxiv

Archive for İ

count() optimization (performance test)

Bu yazıda count(column_name) və count(*) optimizasiyası haqqında danışacıq. Sadə yollarla count(*) sərf edilən vaxtı bir neçə dəfə azalda bilərik. Lakin bu mövzunu daha yaxşı anlamanız üçün bəzi MySQL internals mövzularına qısaca olaraq toxunmalıyıq.
İnnoDB-də primary key və secondary index(istənilən digər key) anlayışı. primary key hər cədvəldə 1 dənə olur secondary index isə çoxsaylı. Lakin İnnoDB-nin clustered index strukturu hər secondary key-də sanki bir primary key saxlayır. Bunu sadə sözlərnən belə izah etmək olar ki, hər secondary index=secondary index+primary key. Və istənilən query-də MySQL istənilən məlumatı primary key vasitəsilə tapır. Yəni select etdikdə sanki ilk öncə həmin row-nun primary key-si daha sonra secondary key-si və daha sonra məlumatın özü tapılır. Az öncə qeyd etdiyim kimi hər secondary key özlüyündə primary key-dən ~parça~ saxlayır dolayısı ilə burdan belə nəticə çıxarmaq olar ki, göstərilən qaydanın əksi də doğrudur.
Yəni secondary index-dən istifadə etməklə primary key-i tapmaq olar! Çox uzatmıram keçək işə 😉

İlk öncə cədvəlimizə baxaq

CREATE TABLE `sales` (
  `SALES_ID` int(8) NOT NULL AUTO_INCREMENT,
  `CUSTOMER_ID` decimal(8,0) NOT NULL,
  `PRODUCT_ID` decimal(8,0) NOT NULL,
  `SALE_DATE` datetime NOT NULL,
  `QUANTITY` decimal(8,0) NOT NULL,
  `SALE_VALUE` decimal(8,0) NOT NULL,
  `DEPARTMENT_ID` decimal(8,0) DEFAULT '0',
  `SALES_REP_ID` decimal(8,0) DEFAULT '0',
  `GST_FLAG` decimal(8,0) DEFAULT NULL,
  `sale_status` char(1) DEFAULT NULL,
  `FREE_SHIPPING` char(1) DEFAULT '',
  `DISCOUNT` decimal(8,0) unsigned DEFAULT '0',
  PRIMARY KEY (`SALES_ID`),
  KEY `sales_cust_idx` (`CUSTOMER_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=2500004 DEFAULT CHARSET=latin1

Gördüyümüz kimi cədvəlimizdə sales_id=primary key, sales_cust_idx=secondary key.

İndi isə sadə və həmişə gördüyümüz select count(*)-a baxaq yəni bütün row sayını tapaq.

mysql> select count(*) from sales;
+----------+
| count(*) |
+----------+
|  2500003 |
+----------+
1 row in set (0.58 sec)

Vaxt: 0.58 saniyə

Yuxarıda kiçik nəzəriyyə girişinə sübut kimi QEP-ə baxdıqda görürük ki, həqiqətən də MySQL count üçün secondary key-dən istifadə edir.

mysql> explain select count(*) from sales\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: sales
         type: index
possible_keys: NULL
          key: sales_cust_idx
      key_len: 4
          ref: NULL
         rows: 2489938
        Extra: Using index
1 row in set (0.00 sec)

key: sales_cust_idx = secondary index.

Sual: biz görmüşük ki, həmişə primary key digər key-lərdən daha sürətlidir. Niyə primary key istifadə etmirik? Axı həmişə köməyimizə gəlir

Cavab: MySQL optimizer bizdən daha yaxşı bilir.

Primary key vasitəsilə count edək:

mysql> select count(*) from sales ignore index(sales_cust_idx);
+----------+
| count(*) |
+----------+
|  2500003 |
+----------+
1 row in set (0.71 sec)

QEP:

mysql> explain select count(*) from sales ignore index(sales_cust_idx)\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: sales
         type: index
possible_keys: NULL
          key: PRIMARY
      key_len: 4
          ref: NULL
         rows: 2489938
        Extra: Using index
1 row in set (0.00 sec)

key: PRIMARY
Vaxt : 0.71 saniyə
0.71 və 0.58 bilənlər bilir ki, hətta 0.001-in əhəmiyyəti var.

Daha sonra count(*)-un istifadə edildiyi 2-ci ümumi hala baxaq. İD-si 50-dən böyük olanları count-layaq.

mysql> select count(*) from sales where sales_id>50;
+----------+
| count(*) |
+----------+
|  2499953 |
+----------+
1 row in set (0.92 sec)

Vaxt 0.92 saniyə

Bu query-ni dəyişirik, aşağıdakı kimi yazırıq və fərqə baxırıq:

mysql> select (select count(*) from sales)-count(*) as count from sales where sales_id<=50;
+---------+
| count   |
+---------+
| 2499953 |
+---------+
1 row in set (0.60 sec)

Vaxt: 0.60

0.92 – 0.60=0.32 daha sürətlidir…

Davam edərək count()-un istifadə edildiyi daha bir yerə baxaq.

create table colors(
color_name varchar(15) not null
);

insert into colors values('blue'),('blue'),('blue'),('yellow'),('yellow'),('yellow'),('yellow');

Sual: cədvəldə hər rəngdən neçə ədəd var?

Sınayaq:

mysql> select count(color_name) from colors where color_name='blue' or color_name='yellow';
+-------------------+
| count(color_name) |
+-------------------+
|                 7 |
+-------------------+
1 row in set (0.00 sec)


mysql> select count(color_name) from colors where color_name='blue' and color_name='yellow';
+-------------------+
| count(color_name) |
+-------------------+
|                 0 |
+-------------------+
1 row in set (0.00 sec)

Alınmadı 😉

Üsullar:

-- 1
mysql> select sum(if(color_name='blue',1,0)) as blue, count(if(color_name='yellow',1,0)) as yellow from colors;
+------+--------+
| blue | yellow |
+------+--------+
|    3 |      7 |
+------+--------+
1 row in set (0.00 sec)

-- 2
mysql> select sum(color_name='blue') as blue, sum(color_name='yellow') as yellow from colors;
+------+--------+
| blue | yellow |
+------+--------+
|    3 |      4 |
+------+--------+
1 row in set (0.00 sec)

-- 3 count()-lu üsul
mysql> select count(color_name='blue' or NULL) as blue, count(color_name='yellow' or NULL) as yellow from colors;
+------+--------+
| blue | yellow |
+------+--------+
|    3 |      4 |
+------+--------+
1 row in set (0.00 sec)

Təşəkkürlər 😉

MySQL 5.6.10 Query optimizer (performance test)

Təbii ki 5.6.10 versiya ilə bir çox yeniliklər gəlib.
Və əsas səs gətirən hadisələrdən biri Query Optimizer-in inkişafıdır. Çox dərinliyə getmədən nə qədər əlavələrin olduğuna siz də baxa bilərsiniz:

5.5.30 versiya üçün:

mysql [localhost] {msandbox} (employees) > select @@optimizer_switch\G
*************************** 1. row ***************************
@@optimizer_switch:
index_merge=on,
index_merge_union=on,
index_merge_sort_union=on,
index_merge_intersection=on,
engine_condition_pushdown=on
1 row in set (0.00 sec)

5.6.10 versiya üçün:

mysql> select @@optimizer_switch\G
*************************** 1. row ***************************
@@optimizer_switch: 
index_merge=on,
index_merge_union=on,
index_merge_sort_union=on,
index_merge_intersection=on,
engine_condition_pushdown=on,
index_condition_pushdown=on,
mrr=on,
mrr_cost_based=on,
block_nested_loop=on,
batched_key_access=off,
materialization=on,
semijoin=on,
loosescan=on,
firstmatch=on,
subquery_materialization_cost_based=on,
use_index_extensions=on
1 row in set (0.00 sec)

Bəli MySQL optimizer indi daha ağıllıdır necə deyərlər. Və test üçün biz employees database-ini götürəcik. Bu database-i siz də yükləyə bilərsiniz:
employees_db

Və bu database-dəki employees cədvəli. Cədvəldə 300.024 record var.Cədvəl strukturu aşağıdakı kimidir:

mysql> desc employees;
+------------+---------------+------+-----+---------+-------+
| Field      | Type          | Null | Key | Default | Extra |
+------------+---------------+------+-----+---------+-------+
| emp_no     | int(11)       | NO   | PRI | NULL    |       |
| birth_date | date          | NO   |     | NULL    |       |
| first_name | varchar(14)   | NO   |     | NULL    |       |
| last_name  | varchar(16)   | NO   |     | NULL    |       |
| gender     | enum('M','F') | NO   |     | NULL    |       |
| hire_date  | date          | NO   |     | NULL    |       |
+------------+---------------+------+-----+---------+-------+
6 rows in set (0.00 sec)

Dolayısı ilə 1 dənə index var o da primary key.

Test 1:

select emp_no from employees where first_name='Marco'

MySQL 5.6.10:

MySQL 5.5.30:

və yuxarıdakı QEP-dən də aydın olduğu kimi MySQL 5.6.10 test edilmiş query-nin nəticəsini bizə hazırlayıb verməsi üçün 299,645 row-nu oxumalıdır. 5.5.30 isə 300,856.
Lakin query response time-da elə də fərq yoxdur hər 2-si 0.10 sec çəkdi.

Test 2:
Sözsüz ki, məntiqlə düşündükdə belə nəticəyə gəlmək olar ki, əgər biz first_name-lə axtarış ediriksə onu index-ləməliyik:

alter table employees add index(first_name);
select emp_no from employees where first_name='Marco'

MySQL 5.6.10:

MySQL 5.5.30:

QEP-lər tamamilə eynidir. Gördüyümüz kimi emp_no və first_name hər ikisi index-ləndiyi üçün MySQL məlumatı birbaşa index-dən oxuyur.
Bu həmçinin aşağıdakı query-lər üçün də keçərlidir:

select emp_no from employees where first_name like '%mar%';
select emp_no from employees where first_name like 'Mar%';

Təbii ki scan olunacaq row sayı artacaq çünki ehtimallar çoxalır lakin istənilən halda index-dən istifadə olunacaq.

Test 3:
İndi isə query-mizə 1 dənə index-lənməmiş column əlavə edək:

select emp_no,last_name from employees where first_name='Marco';

indiki halda bu index-siz column last_name-dir.
Yazının da yazılma səbəbi məhz şəxsən müəyyən etdiyim MySQL 5.6.10-nun bu gözəl xüsusiyyətdir. Aşağıya diqqət 😉

MySQL 5.6.10:

-- 1
select last_name,emp_no from employees where first_name='Marco';

-- 2
select emp_no,last_name from employees where first_name like 'Marc%';

-- 3
select emp_no,last_name from employees where first_name like 'Mar%';

-- 4
select emp_no,last_name from employees where first_name like 'Ma%';

-- 5
select emp_no,last_name from employees where first_name like 'M%';

Şəkillərdəki EXTRA və rows -lara fikir versəniz görərsiniz ki, MySQL 5.6.10 5 variantın 4-ündə İndex Condition-dan istifadə etdi. Yalnız sonuncu like ‘M%’-dən başqa. Bunun da səbəbi çox aşkardı. M% böyük ehtimal verir bu zaman MySQL Optimizer M-lə başlayan-ları index vasitəsilə yoxlamaq əvəzinə sadəcə full scan etməyi üstün tutur. Optimizer bunun daha faydalı olacağına qənaət gətirib elə biz də həmçinin 🙂

İndi isə eyni testləri MySQL 5.5.30 üçün edək.
MySQL 5.5.30:

-- 1
select last_name,emp_no from employees where first_name='Marco';

-- 2
select emp_no,last_name from employees where first_name like 'Marc%';

-- 3
select emp_no,last_name from employees where first_name like 'Mar%';

-- 4
select emp_no,last_name from employees where first_name like 'Ma%';

-- 5
select emp_no,last_name from employees where first_name like 'M%';

Gördüyünüz kimi istənilən halda Using İndex Condition istifadə olunmadı. Səbəb? Çünki bu xüsusiyyət yalnız MySQL 5.6.10-da var. Ümumiyyətlə bu versiya çox səs gətirəcək deyə bilərik. Həmçinin siz MariaDB 10.0-a da baxa bilərsiniz. Bu MySQL 5.6.10 ilə eynidir.

Bəs nədir bu Using İndex Condition? Daha ətraflı: index-condition-pushdown-optimization
Qısa olaraq: ICP can reduce the number of times the storage engine must access the base table and the number of times the MySQL server must access the storage engine.

Onu da qeyd etməkdə fayda var ki, siz də öz localhost/server-inizdə 2 ve daha artıq MySQL versiyanı qurub test edə bilərsiniz. Bunun üçün xüsusi tool MySQL Sandbox-dan istifadə edə bilərsiniz. Bu haqda artıq məqalə yazmışam:
Sandbox on Centos

Təşəkkürlər 😉

Prefix indexes vs. Full indexes (performance test)

Artıq bir neçə dəfə query performansının aşağı olmasının səbəbini index-ləmədə buraxılan səhvlərdə tapıram.
google-dan copy-paste etdikdən sonra düzgün işləyən query-i 2 qat zəifləməsin nə etsin? 😉
Kiçik index həmişə yaxşıdır deyə bir şey yoxdur. Lütfən hər hansı bir dəyişiklik etməmişdən əvvəl dəfələrlə test edin.

Full index : bütöv bir column-u index-ləmək.
Prefix index: yalnız müəyyən leftmost hissəni index-ləmək.

Təbii ki bəzən prefix index-lərin faydası olur lakin faydasından çox ziyanı da ola bilər, bunu da indi test edəcik.
Çox böyük cədvəl götürmürəm indiki halda 128.400 row-su olanla başlamaq olar. Sizin əlinizdə daha böyük data-lı cədvəl varsa test edin və əlavələri sizin müəllifliyiniz altında yazıya elavə edim.

Nümunə cədvəlimiz city-dir.

CREATE TABLE `city_demo` (
  `city` varchar(26) NOT NULL,
 )

Test without index:

select * from city_demo;

Time: 0.1018

Test with full index:

alter table city_demo add index(city);
select * from city_demo;

Time: 0.0829

Test with prefix index:

alter table city_demo drop index city;
alter table city_demo add index(city(7));
select * from city_demo;

Time: 0.1035

Indi isə diqqət edin. index-siz select* = prefix indexli select * . QEP(query execution plan)-e baxdıqda da görərik ki, hər iki query üçün full table scan müşahidə olunur. Dolayısı ilə biz bu prefix index-i boş yerə əlavə etmiş oluruq.
Testə davam edək.
Test without index:

select city from city_demo where city like 'Sa%';

Time: 0.0753

Test with full index:

alter table city_demo add index(city);
select city from city_demo where city like 'Sa%';

Time: 0.0101

Test with prefix index:

alter table city_demo drop index city;
alter table city_demo add index(city(7));
select city from city_demo where city like 'Sa%';

Time: 0.0249

Nisbətən yaxşıdır lakin yenə də full index-dən daha zəifdir. Əvvəlkinə baxdıqda indi deyə bilərik ki, bəli prefix index effektiv olaraq istifadə olundu lakin performance-ı 0.01 qədər daha aşağı oldu.

Nəticə: Prefix index sizə daha çox mb qazandıracaq. Yəni, varchar(20) üçün full index 22 byte, index(7) isə 9 byte yer tutmuş olacaq. Lakin mb qazanmaq niyyəti ilə query-ni zəiflətmə riskiniz var. Bundan əlavə Prefix İndex-li column-u Order by və Group by-da həmçinin “İndex Covering”-də istifadə etmək olmur. Dolayısı ilə Prefix index-dən çox ehtiyatla və test edərək istifadə etmək lazımdır.

Deyək ki siz düşündünüz ki, prefix index sizə tam uyğundur və hər şeyi nəzərə aldınız. Ən uyğun uzunluğu (yəni add index(city(x))) necə hesablamalıyıq. Bunun qəşəng çox sadə bir üsul var. Bunun üçün ilk öncə ən çox təkrarlanan şəhərləri tapırıq:

mysql> SELECT COUNT(*) AS cnt, city
    -> FROM city_demo
    -> GROUP BY city
    -> ORDER BY cnt DESC
    -> LIMIT 10;
+-----+----------------------------+
| cnt | city                       |
+-----+----------------------------+
| 425 | London                     |
| 223 | Mysore                     |
| 222 | Livorno                    |
| 220 | Santiago de los Caballeros |
| 220 | Acua                       |
| 220 | Ashgabat                   |
| 219 | Miyakonojo                 |
| 219 | Kimberley                  |
| 219 | Halisahar                  |
| 219 | Daugavpils                 |
+-----+----------------------------+
10 rows in set (0.16 sec)

Əgər fikir verdinizsə bütün qiymətlər 220-420 arasındadır.
Daha sonra isə ən çox təkrarlanan prefix-ləri tapırıq. Bir neçə dəfə test etdikdən sonra görmək olar ki, həqiqətən də 7 bizə ən uyğunudur:

mysql> SELECT COUNT(*) AS cnt,
    -> LEFT(city,7) AS pref
    -> FROM city_demo
    -> GROUP BY pref
    -> ORDER BY cnt DESC
    -> LIMIT 10;
+-----+---------+
| cnt | pref    |
+-----+---------+
| 435 | Santiag |
| 434 | Valle d |
| 430 | San Fel |
| 425 | London  |
| 223 | Mysore  |
| 222 | Livorno |
| 220 | Ashgaba |
| 220 | Acua    |
| 219 | Nha Tra |
| 219 | Konotop |
+-----+---------+

220-430 arası dəyişir. Yəni təqribən bərabərdir.

Prefix index-in performance təsirini ölçmək üçün siz də öz data-nızla testlər edin və onu bizimlə paylaşın.
Təşəkkürlər 😉

İP adreslərin düzgün şəkildə saxlanılması (performance test)

Mart 14, 2013 6 şərh

Bu yazı şəxsi araşdırmam və tapıntımdan ibarət olub mənim özümə də çox böyük zövq vermək üzərədir.
Yazıda İP adreslərin 2 yolla cədvəldə saxlanılması və bu 2 yolun performance fərqlərindən danışılacaq.
İlk öncə nümunə 2 cədvəlimizi yaradaq :

create table ip_int(
ip int unsigned not null
);


create table ip_varchar(
ip varchar(15) not null
);

1ci cədvəldə biz İP-ni integer kimi 2-ci cədvəldə isə string kimi saxlayacıq.
SUAL: İP adres 127.255.255.255 kimi bir şeydir tərkibində nöqtələr var. bunu integer kimi necə saxlamaq olar ki?
CAVAB: Bunun üçün MySQL-də xüsusi 2 funksiya vardır. function_inet-atonfunction_inet-ntoa

Və yuxarıdakı 2 cədvəlimizin hər birinə 1 milyon İP insert edək. Bunun üçün də xüsusi 2 procedure yazdım ki iş rahat olsun.

delimiter //
CREATE PROCEDURE insert_ip_int()
BEGIN 
 	SET @ip='127.255.255.255'; 
 	SET @counter=1;
	insert_loop: LOOP 
		IF (@counter>1000000) THEN 
		LEAVE insert_loop; 
		ELSE
        INSERT INTO ip_int(ip) VALUES(INET_ATON(@ip)); 
		  SET @counter=@counter+1; 
		END IF; 
	END LOOP insert_loop; 
END //

-----------------------------------------------------------------------------

delimiter //
CREATE PROCEDURE insert_ip_vacrhar()
BEGIN 
 	SET @ip='127.255.255.255'; 
 	SET @counter=1;
	insert_loop: LOOP 
		IF (@counter>1000000) THEN 
		LEAVE insert_loop; 
		ELSE
        INSERT INTO ip_varchar(ip) VALUES(@ip); 
		  SET @counter=@counter+1; 
		END IF; 
	END LOOP insert_loop; 
END //

Performance test 1 :İnsert speed:
ip_int cədvəlinə 1 milyon sadə insert:

mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)

mysql> call insert_ip_int();
Query OK, 0 rows affected (40.99 sec)

mysql> set autocommit=1;
Query OK, 0 rows affected (0.00 sec)

ip_varchar cədvəlinə 1 milyon sadə insert:

mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)

mysql> call insert_ip_vacrhar();
Query OK, 0 rows affected (48.02 sec)

mysql> set autocommit=1;
Query OK, 0 rows affected (0.00 sec)

integer şəklində insert təqribən 8 saniyə daha sürətlidir. Bilənlər bilir ki 0.001 saniyənin belə qiyməti çoxdu 😉

Performance test 2 :The Total MB:
2 cədvəlin disk-də nə qədər yer tutduğuna baxaq:

SELECT  
TRUNCATE((data_length+index_length)/1024/1024,4) AS total_mb
FROM information_schema.`TABLES`
WHERE `TABLE_SCHEMA`='my_test' AND `table_name`='ip_int';

ip_int: 29.5625

SELECT  
TRUNCATE((data_length+index_length)/1024/1024,4) AS total_mb
FROM information_schema.`TABLES`
WHERE `TABLE_SCHEMA`='my_test' AND `table_name`='ip_varchar';

ip_varchar: 41.5625

41.5625 MB – 29.5625 MB = 12 MB. və yenə də əgər bir cədvəl digərindən daha yüngüldürsə demək ki query-si də daha sürətlidir.

Performance test 3 :SELECT * without index:
İndi isə hər 2 cədvələ select * verib sürətinə baxacıq. İndiki halda index-dən istifadə etmirik.

mysql> SELECT * from ip_int;
1000000 rows in set (0.77 sec)


mysql> SELECT * from ip_varchar;
1000000 rows in set (0.85 sec)

0.08 saniyə daha sürətlidir.

Performance test 4 :SELECT * with index:
İndi isə index-ləyib select verək:

select * from ip_int; 
1000000 rows in set (0.70 sec)

select * from ip_varchar;
1000000 rows in set (0.80 sec)

0.1 saniyə daha sürətlidir.

Performance test 5 :ALTER table speed:

alter table ip_int add index(ip);
Duration for 1 query: 5.119 sec.

alter table ip_varchar add index(ip); 
Duration for 1 query: 7.283 sec.

2.64 saniyə daha sürətlidir.

Nuş olsun 😉

Müəyyən həcmdən böyük cədvəllər üçün EVENT

Delimiter $$
CREATE EVENT event_huge_table_ ON SCHEDULE EVERY 20 second
COMMENT "Mueyyen hecmden boyuk cedveller uzerinde is" DO 
BEGIN 
    DECLARE v_total_mb FLOAT(10,4); 
    declare v_last_row_fetched int default 0;
    
	 DECLARE cursor1 CURSOR FOR
       SELECT 
        sum(TRUNCATE((data_length+index_length)/1024/1024,4)) as total_mb
        FROM information_schema.`TABLES`
        where table_schema='mysqlspp'
        group by table_name;

   declare continue handler for not found set v_last_row_fetched=1;
   
	set v_last_row_fetched=0;
	 
	 OPEN cursor1;
      cursor_loop: LOOP FETCH cursor1 INTO v_total_mb; 
 
        IF v_last_row_fetched=1 THEN
				leave cursor_loop;
        END IF; 
        
        
        if v_total_mb>20 then
           insert into test_zerofill(name) values('dusen var?');
        end if;
		     
       end loop cursor_loop;
    close cursor1;
    set v_last_row_fetched=0;
END $$
Kateqoriyalar: My Stored Routines

Installing MySQL Sandbox 3.0.30 on CentOS 6.3

Bir server-də 1-dən artıq MySQL server işləyə bilməz.Çünki hər bir MySQL install olunarkən default olaraq data directory /var/lib/mysql və basedir kimi /usr olur. Dolayısı ilə conflict baş verir.
Deyək ki bizim default server-imiz MySQL 5.6.10-dur. Və biz MySQL 5.5.30-u test etmək istəyirik. Dolayısı ilə 5.6.10-u silib 5.5.30 yazmaq biraz ciddi məsələdir. Sırf test üçün bunu etməyə gərək yoxdur.

Eyni Server-də 1-dən artıq MySQL-i install edib işlətməyə bizə MySQL Sandbox adlı çox gözəl bir tool kömək edir…
Məndə default installation MySQL 5.6.10-dur. Və Sandbox-a MySQL 5.5.30-u install edib işlədəcik.
İlk öncə Sandbox-un qurulması çox asand bir şəkildə:
1.

[root@localhost ~]# yum install cpan
[root@localhost ~]# yum install perl-YAML
[root@localhost ~]# yum install perl-Test-Simple

2.

[root@localhost ~]# cpan MySQL::Sandbox

Ən sonda belə bir yazı gələcək:

 GMAX/MySQL-Sandbox-3.0.30.tar.gz
  /usr/bin/make install  -- OK

Sandbox-umuz hazırdı. İndi isə MySQL 5.5.30-un tar versiyasını download etmək lazımdır.Download Link

mysql-5.5.30-linux2.6-x86_64.tar.gz -u yerləşdiririk home-a. Yəni mən belə etdim. /home/sh/Documents-ə yerləşdirdim.

Daha sonra Sandbox-a bu MySQL-imizi install edirik:

[sh@localhost ~]$ make_sandbox /home/sh/Documents/mysql-5.5.30-linux2.6-x86_64.tar.gz
unpacking /home/sh/Documents/mysql-5.5.30-linux2.6-x86_64.tar.gz
.
.
<<5.5>>
    The MySQL Sandbox,  version 3.0.30
.
.
loading grants
... sandbox server started
Your sandbox server was installed in $HOME/sandboxes/msb_5_5_30

Vəssalam hazırdır. İndi də Sandbox-u start edib MySQL 5.5.30 ilə i.ləyə bilərik. Bunun üçün uyğun directory-yə gedib:

[sh@localhost ~]$ cd /home/sh/sandboxes/msb_5_5_30
[sh@localhost msb_5_5_30]$ ./use
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.5.30 MySQL Community Server (GPL)

Bəli təbriklər artıq bizim əlimizdə eyni Linux-da 2 MySQL server var 😉
Onu da qeyd etmək lazımdır ki yeni MySQL-imiz tam funksionaldır. Yani sanki rpm installation-dur. Heç bir çatışmazlığı yoxdur.
Sandbox-dan:

mysql [localhost] {msandbox} ((none)) > select version();
+-----------+
| version() |
+-----------+
| 5.5.30    |
+-----------+
1 row in set (0.00 sec)

mysql [localhost] {msandbox} ((none)) > select @@default_storage_engine;
+--------------------------+
| @@default_storage_engine |
+--------------------------+
| InnoDB                   |
+--------------------------+
1 row in set (0.00 sec)

Default-dan:

mysql> select version();
+------------+
| version()  |
+------------+
| 5.6.10-log |
+------------+
1 row in set (0.00 sec)


mysql> select @@default_storage_engine;
+--------------------------+
| @@default_storage_engine |
+--------------------------+
| InnoDB                   |
+--------------------------+
1 row in set (0.00 sec)

Və indi siz bu 2 fərqli MySQL versiya üzərində test-lər apara bilərsiniz
Sandbox-u stop etmək üçün :

[sh@localhost msb_5_5_30]$ ./stop

Təşəkkürlər 😉