Više detalja o 1,7 terabajtnoj Firebird SQL bazi podataka
Alexey Kovyazin, 26-мај-2014
Пре неколико дана објавили смо чланак о нашим тестовима, посвећен односу између перформанси Firebird-а и раста базе података, где смо тестирали (између осталог) Firebird SQL базу од 1,7 терабајта. Овде можете пронаћи више детаља о тако великој бази података.
Табеле
У табели 1 можете пронаћи листу табела са кључним карактеристикама. Ова статистика је узета помоћу gstat -a -r и интерпретирана нашим IBAnalyst алатом.
| Табела | Записи | Дужина записа, бајтова | Странице података | Величина табеле, Mb | Величина индекса, Mb | Укупно, % |
|---|---|---|---|---|---|---|
| ORDER_LINE | 6300024797 | 60.09 | 38880344 | 607505.3 | 50582.3 | 34 |
| STOCK | 2100000000 | 298.88 | 43783806 | 684121.9 | 15809.61 | 39 |
| ORDERS | 630004141 | 29.00 | 2692324 | 42067.56 | 4250.38 | 2 |
| HISTORY | 630000434 | 48.77 | 3446455 | 53850.86 | 0.00 | 3 |
| CUSTOMER | 630000000 | 577.52 | 24226054 | 378532.0 | 8675.78 | 21 |
| NEW_ORDER | 188999981 | 13.00 | 623764 | 9746.31 | 1260.84 | 1 |
| DISTRICT | 210000 | 103.92 | 1860 | 29.06 | 1.27 | ~0 |
| ITEM | 100000 | 82.73 | 756 | 11.81 | 0.52 | ~0 |
| WAREHOUSE | 21000 | 97.90 | 179 | 2.80 | 0.11 | ~0 |
Табела 1. Табеле и њихови главни параметри у Firebird SQL бази од 1,7 терабајта
Као што можете видети, највећа табела је ORDER_LINE - садржи више од 6 милијарди записа. Њена величина је око 600Gb и постоји 50Gb индекса за ову табелу. Ова табела заузима 34% базе података.
Табела STOCK је такође веома велика - садржи ~2 милијарде записа. Иако је број записа мањи него у табели ORDER_LINE, STOCK заузима ~680Gb у бази (39%), јер је дужина записа у STOCK-у 298.88 бајтова наспрам само 60.09 бајтова у ORDER_LINE-у. Сходно томе, величина повезаних индекса за STOCK је само 15Gb.
Трећа највећа табела, CUSTOMER, има још већу дужину записа - 577.52 бајта, и заузима 378Gb (21%) са само 630 милиона записа.
Индекси
Нема много индекса у овој бази података, јер је дизајнирана само за тестове - већина табела има само 1 индекс - примарни кључ. У апликацијама из стварног света, програмери креирају многе индексе да би задовољили конкретне захтеве корисника, али овде су индекси усмерени на најбржа уметања и ажурирања података - као резултат, величина индекса је само 5-10% величине табеле, док је обично 30-50% (ако је величина индекса већа од 50% величине табеле, размотрите редизајн шеме базе података, или можда одбаците бескорисне или неефикасне индексе).
У табели 2 можете пронаћи листу свих индекса у овој бази података и њихове кључне карактеристике, узете из gstat статистике и анализиране помоћу IBAnalyst:
| Индекс | Табела | Дубина | Број кључева | Дужина кључа, бајтова | Број јединствених кључева | Величина, Mb |
|---|---|---|---|---|---|---|
| ORDER_LINE_PK | ORDER_LINE | 4 | 6300024797 | 1.41 | 6300024797 | 50582.34 |
| STOCK_PK | STOCK | 4 | 2100000000 | 1.00 | 2100000000 | 15809.61 |
| ORDERS_PK | ORDERS | 3 | 630004141 | 1.01 | 630004141 | 4250.38 |
| CUSTOMER_LAST | CUSTOMER | 3 | 630000000 | 0.00 | 1000 | 4029.64 |
| CUSTOMER_PK | CUSTOMER | 3 | 630000000 | 1.01 | 188999981 | 1260.84 |
| NEW_ORDER_PK | NEW_ORDER | 3 | 188999981 | 1.01 | 188999981 | 1260.84 |
| DISTRICT_PK | DISTRICT | 2 | 210000 | 1.37 | 210000 | 1.27 |
| ITEM_PK | ITEM | 2 | 100000 | 1.00 | 100000 | 0.52 |
| WAREHOUSE_PK | WAREHOUSE | 2 | 21000 | 1.00 | 21000 | 0.11 |
Табела 2. Индекси Firebird базе од 1,7Tb
Као што можете видети, сви индекси имају веома малу величину кључа - највећа је 1.41, што значи да је индекс веома ефикасно компримован - на пример, примарни индекс за ORDER_LINE садржи 6 милијарди кључева у 50 Gb простора. Ово је веома добар резултат.
Постоје 2 индекса која имају дубину = 4. То значи да мотор треба да изврши 4 читања индексних страница да би пронашао тражену вредност. Препоручује се да дубина индекса не буде већа од 3, а ако је већа, величину странице базе података треба повећати. Међутим, већ имамо максималну величину странице у овој бази (16Kb), тако да морамо да живимо са тим.
Загревање
Пре него што наставимо са упитима, хајде да извршимо „загревање“. Када је база података велика, системски подаци повезани са табелама су такође велики, и потребно је неко време да Firebird кешира потребне системске странице. На пример, табела ORDER_LINE има 10110 показивачких страница. Загревање је неопходно за сваку велику базу података.
Без загревања, прво извршавање упита ће трајати значајно дуже него са загревањем.
Да бисмо загрејали кеш базе података, извршимо низ једноставних упита да учитамо системске податке у кеш:
select first 1 * from ORDER_LINE; select first 1 * from STOCK; select first 1 * from customer; select first 1 * from ORDERS; select first 1 * from ITEM;
Ово је довољно за тако једноставну шему података. За велике и сложене базе са стотинама табела, шема загревања може бити много сложенија и треба је пажљиво развити.
Као резултат, потрошња меморије Firebird процеса (Firebird SuperServer 2.5.2 64 бита) расте:

Слика 1. Загревање кеша базе података
Упити
Након загревања можемо покренути неколико типичних упита да проценимо како ће корисници радити са тако великом Firebird базом података: каква ће бити времена одговора за типичне упите и операције читања.
| Упит | План и статистика | Опис |
|---|---|---|
select first 10 w_id, w_name, c_id, c_last<br> from WAREHOUSE, customer<br> where c_w_id = w_id and c_w_id = 10000 |
PLAN JOIN (WAREHOUSE NATURAL,<br> CUSTOMER INDEX (CUSTOMER_PK))<br> STATISTICS<br> Current memory = 166919744<br> Delta memory = 5616<br> Max memory = 166977488<br> Elapsed time= 0.08 sec<br> Buffers = 10000<br> Reads = 1<br> Writes 0<br> Fetches = 51 |
Спајање табеле WAREHOUSE (21000 записа) са CUSTOMER (630 милиона записа), са условом за одређено складиште |
select count(*)<br> from WAREHOUSE, customer<br> where c_w_id = w_id and c_w_id = 10000 |
PLAN JOIN (WAREHOUSE INDEX (WAREHOUSE_PK),<br> CUSTOMER INDEX (CUSTOMER_PK))<br> COUNT<br> ============<br> 30000<br> <br> Current memory = 166918560<br> Delta memory = -1184<br> Max memory = 166977488<br> Elapsed time= 0.16 sec<br> Buffers = 10000<br> Reads = 1175<br> Writes 0<br> Fetches = 60040 |
Бројање записа за претходни упит. |
SELECT first 10 *<br> FROM ORDER_LINE<br> WHERE OL_W_ID = 10050 |
PLAN (ORDER_LINE INDEX (ORDER_LINE_PK))<br> STATISTICS<br> Current memory = 167013640<br> Delta memory = 95080<br> Max memory = 167055968<br> Elapsed time= 0.80 sec<br> Buffers = 10000<br> Reads = 10285<br> Writes 0<br> Fetches = 10424 |
Упит на највећу табелу ORDER_LINE (~6 милијарди записа) са условом за избор записа order_line за одређени ID складишта. Пошто је примарни кључ ORDER_LINE_PK сложен и садржи ID складишта (CONSTRAINT ORDER_LINE_PK: Primary key (OL_W_ID, OL_D_ID, OL_O_ID, OL_NUMBER), ефикасно се користи у овом упиту. |
SELECT count(*)<br> FROM ORDER_LINE<br> WHERE OL_W_ID = 10050; |
PLAN (ORDER_LINE INDEX (ORDER_LINE_PK))<br> <br> COUNT<br> ============<br> 299509<br> Current memory = 167125464<br> Delta memory = -7160<br> Max memory = 167267976<br> Elapsed time= 3.41 sec<br> Buffers = 10000<br> Reads = 1994<br> Writes 0<br> Fetches = 599170 |
Бројање за претходни упит. Други упит са истим параметрима ће бити много бржи, али упити са различитим параметрима показују сличан резултат. |
Select first 10 w_id, w_name, c_id, c_last<br> rom WAREHOUSE, CUSTOMER<br> where c_w_id = w_id and (c_w_id > 8000)<br> and (c_w_id < 10000) |
PLAN JOIN (WAREHOUSE INDEX (WAREHOUSE_PK),<br> CUSTOMER INDEX (CUSTOMER_PK))<br> <br> STATISTICS<br> Current memory = 167687664<br> Delta memory = -651888<br> Max memory = 168931400<br> Elapsed time= 0.19 sec<br> Buffers = 10000<br> Reads = 31<br> Writes 0<br> Fetches = 63 |
Упит са спајањем и 2 услова. |
| select first 10 c1.C_ID, c1.C_FIRST, c1.C_LAST, o1.O_ID,<br> o1.O_OL_CNT, i1.I_NAME, i1.I_PRICE, ol1.OL_AMOUNT<br> from customer c1<br> join orders o1 on (c1.c_w_id = o1.O_w_ID<br> and c1.C_D_ID = o1.O_D_ID and c1.C_ID = o1.O_C_ID)<br> join ORDER_LINE ol1 on (ol1.ol_w_id = c1.C_W_ID<br> and ol1.OL_D_ID = c1.C_D_ID<br> and ol1.OL_O_ID = o1.O_ID)<br> join Item i1 on (ol1.OL_I_ID = i1.i_id)<br> where o1.o_d_id = 1 and o1.o_w_id = 1 and c1.c_id = 10; | PLAN JOIN (C1 INDEX (CUSTOMER_PK),<br> O1 INDEX (ORDERS_PK),<br> OL1 INDEX (ORDER_LINE_PK),<br> I1 INDEX (ITEM_PK))<br> <br> STATISTICS<br> Current memory = 166807128<br> Delta memory = 6016<br> Max memory = 166879200<br> Elapsed time= 0.20 sec<br> Buffers = 9999<br> Reads = 1<br> Writes 0<br> Fetches = 4960 | Упит за приказ детаља за одређеног купца у одређеном складишту и округу. Демонстрира перформансе сложенијих спајања. |
Резиме
Као што видите, Firebird база података од 1,7 терабајта показује прилично добре перформансе за уобичајене упите за читање. Ако је упит добро дизајниран и користи добре индексе, перформансе су добре чак и на веома великој бази података. Наравно, постоје проблематичне тачке, као што је дуго време преузимања за веома велике скупове података и дуго време за операције бројања (пошто Firebird посећује све странице да би добио тачан број записа за одређени упит у одређеној трансакцији), али ове проблематичне тачке су добро познате искусним Firebird програмерима, и постоје методе за дизајнирање базе података на начин који их заобилази.
Али шта је са деградацијом перформанси за уметања и ажурирања? Да ли је могуће то компензовати паметним подешавањем Firebird конфигурације?
У следећем чланку размотрићемо опције подешавања за Firebird базу података од 1,7 терабајта - појачаћемо нашу птицу и учинити да лети.