Əsas səhifə > Performance tests and tips > count() optimization (performance test)

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😉

  1. Hələlik heç bir şərh yoxdur
  1. No trackbacks yet.

Bir cavab yazın

Sistemə daxil olmaq üçün məlumatlarınızı daxil edin və ya ikonlardan birinə tıklayın:

WordPress.com Loqosu

WordPress.com hesabınızdan istifadə edərək şərh edirsinz. Çıxış / Dəyişdir )

Twitter rəsmi

Twitter hesabınızdan istifadə edərək şərh edirsinz. Çıxış / Dəyişdir )

Facebook fotosu

Facebook hesabınızdan istifadə edərək şərh edirsinz. Çıxış / Dəyişdir )

Google+ foto

Google+ hesabınızdan istifadə edərək şərh edirsinz. Çıxış / Dəyişdir )

%s qoşulma

%d bloqqer bunu bəyənir: