Hûn dikarin li ser bingeha KDB+, zimanê bernamenûsê Q çi ne, hêz û qelsiyên wan çi ne di berê min de bixwînin û bi kurtî di pêşgotinê de. Di gotarê de, em ê karûbarek li ser Q bicîh bikin ku dê pêvajoya daneya gihîştî pêvajoyê bike û her hûrdem di moda "dema rast" de fonksiyonên berhevokê yên cihêreng hesab bike (ango, ew ê dem hebe ku her tiştî berî beşa din a daneyê hesab bike). Taybetmendiya sereke ya Q ev e ku ew zimanek vektor e ku dihêle hûn ne bi tiştên yekane, lê bi rêzikên wan, rêzikên rêzan û tiştên din ên tevlihev tevbigerin. Zimanên wekî Q û xizmên wê K, J, APL bi kurtbûna xwe navdar in. Pir caran, bernameyek ku çend ekranên kodê bi zimanek naskirî mîna Java digire, dikare di çend rêzan de li ser wan were nivîsandin. Ya ku ez dixwazim di vê gotarê de destnîşan bikim ev e.

Pîrozbahiyê
KDB+ databasek stûnek e ku li ser mîqdarên pir mezin ên daneyê, ku bi rengek taybetî (bi taybetî ji hêla demê ve) hatî ferman kirin e. Ew di serî de di saziyên darayî - bank, fonên veberhênanê, pargîdaniyên bîmeyê de tê bikar anîn. Zimanê Q zimanê navxweyî yê KDB+ ye ku dihêle hûn bi vê daneyê re bi bandor bixebitin. Îdeolojî Q kurtî û karîgerî ye, lê zelalî tê qurbankirin. Ev ji hêla rastiyê ve tête rastdar kirin ku zimanê vektor dê di her rewşê de dijwar be, û kurtahî û dewlemendiya tomarkirinê dihêle hûn beşek pir mezin a bernameyê li ser yek ekranê bibînin, ku di dawiyê de fêmkirina wê hêsantir dike.
Di vê gotarê de em di Q de bernameyek bêkêmasî pêk tînin û dibe ku hûn bixwazin wê biceribînin. Ji bo vê yekê, hûn ê hewceyê Q-ya rastîn bikin. Hûn dikarin guhertoya 32-bit belaş li ser malpera pargîdaniya kx dakêşin - . Li wir, heke hûn eleqedar in, hûn ê agahdariya referansê li ser Q, pirtûkê bibînin û gotarên cuda li ser vê mijarê.
Formulkirina pirsgirêkê
Çavkaniyek heye ku her 25 milîsaniyeyekê tabloyek bi daneyan dişîne. Ji ber ku KDB+ di serî de di darayî de tê bikar anîn, em ê texmîn bikin ku ev tabloyek danûstendinan (bazirganî) ye, ku stûnên jêrîn hene: dem (dem bi milî çirkeyan), sym (navê pargîdaniyê li ser borsayê - IBM, AAPL,…), biha (bihaya ku hîseyên pê hatine kirîn), mezinahî (mezinahiya danûstendinê). Navbera 25 milîsaniyeyan kêfî ye, ne pir piçûk û ne pir dirêj e. Hebûna wê tê vê wateyê ku dane ji karûbarê jixwe tamponkirî tê. Dê hêsan be ku meriv tampon li ser milê karûbarê bicîh bîne, di nav de tamponkirina dînamîkî li gorî barkirina heyî, lê ji bo sadebûnê, em ê balê bikişînin ser navberek sabît.
Pêdivî ye ku karûbar her hûrdem ji bo her sembola gihîştî ji stûna sym komek fonksiyonên berhevkirinê bijmêre - bihayê herî zêde, nirxa navîn, mezinahiya berhevokê, hwd. agahiyên kêrhatî. Ji bo sadebûnê, em ê texmîn bikin ku hemî fonksiyon dikarin bi zêdebûnê bêne hesibandin, ango. ji bo bidestxistina nirxek nû, bes e ku meriv du hejmaran zanibe - nirxa kevn û ya hatî. Mînakî, fonksiyonên max, navîn, sum xwedî vê taybetiyê ne, lê fonksiyona navîn tune.
Di heman demê de em ê texmîn bikin ku herikîna daneya hatî dema fermankirî ye. Ev dê fersendê bide me ku em tenê bi deqeya paşîn re bixebitin. Di pratîkê de, ji bo ku hin nûvekirin dereng bin, bes e ku meriv bi hûrguliyên heyî û yên berê re bixebite. Ji bo sadebûnê, em ê vê rewşê nenirxînin.
Fonksiyonên kombûnê
Fonksiyonên berhevkirinê yên pêwîst li jêr têne rêz kirin. Min bi qasî ku pêkan ji wan girt da ku barê karûbarê zêde bike:
- bilind - max biha - herî zêde bihayê per minute.
- kêm - bihayê min - herî kêm bihayê per minute.
- firstPrice - bihayê yekem - bihayê yekem per minute.
- lastPrice - buhaya dawîn - buhaya dawîn her deqîqe.
- firstSize - mezinahiya yekem - mezinahiya bazirganiya yekem per hûrdem.
- lastSize - mezinahiya paşîn - mezinahiya bazirganiya paşîn di deqîqeyek de.
- numTrades - jimartin i - hejmara esnafan per xulek.
- hejm - mezinahiya berhevokê - berhevoka mezinahiyên bazirganiyê di hûrdemê de.
- pvolume - bihaya berhevokê - berhevoka bihayên her hûrdemê, ji bo avgPrice pêdivî ye.
- - Bihayê guhêrbar * mezinahî - hêjmara giştî ya danûstendinan di hûrdemê de.
- avgPrice – pvolume%numBazirganî – nirxê navînî her deqîqe.
- avgSize - volume%numTrades - mezinahiya bazirganiyê ya navîn her hûrdem.
- vwap - veguhertina%volum - nirxa navînî ya her hûrdemê li gorî mezinahiya danûstendinê.
- cumVolume - berhevoka berhevokê - mezinahiya danûstendinan di tevahiya demê de berhev kiriye.
Ka em tavilê li ser xalek ne diyar nîqaş bikin - meriv çawa van stûnan ji bo yekem car û ji bo her deqeya paşîn dest pê dike. Pêdivî ye ku hin stûnên celebê firstPrice her carê bêne desteser kirin da ku nirxa wan ne diyar be. Cûreyên cildên din divê her tim li ser 0 bêne danîn. Her weha stûn hene ku pêdivî bi nêzîkbûnek hevgirtî heye - bo nimûne, cumVolume divê ji deqeya berê were kopî kirin, û ji bo ya yekem were danîn ser 0. Werin em van hemî pîvanan bi karanîna daneyên ferhengê saz bikin. cure (analog bi tomarekê):
// list ! list – создать словарь, 0n – float null, 0N – long null, `sym – тип символ, `sym1`sym2 – список символов
initWith:`sym`time`high`low`firstPrice`lastPrice`firstSize`lastSize`numTrades`volume`pvolume`turnover`avgPrice`avgSize`vwap`cumVolume!(`;00:00;0n;0n;0n;0n;0N;0N;0;0;0.0;0.0;0n;0n;0n;0);
aggCols:reverse key[initWith] except `sym`time; // список всех вычисляемых колонок, reverse объяснен ниже
Min ji bo rehetiyê sem û dem li ferhengê zêde kir, naha initWith rêzek amade ye ji tabloya berhevkirî ya dawîn, li wir dimîne ku meriv nîşan û dema rast destnîşan bike. Hûn dikarin wê bikar bînin ku rêzên nû li tabloyek zêde bikin.
Dema ku fonksiyonek berhevkirinê biafirînin em ê hewceyê aggCols bibin. Divê lîste ji ber rêza ku bilêvkirinên di Q de têne nirxandin (ji rast ber bi çep) vegere. Armanc ew e ku pê hesibandin ku hesab ji bilind berbi cumVolume diçe, ji ber ku hin stûn bi yên berê ve girêdayî ne.
Stûnên ku hewce ne ku ji ya berê di deqeyek nû de bêne kopî kirin, stûna simê ji bo rehetiyê tê zêdekirin:
rollColumns:`sym`cumVolume;
Naha em stûnan li gorî ka divê çawa werin nûve kirin li koman dabeş bikin. Sê celeb dikarin bêne cûda kirin:
- Acumulator (volim, gemar, ..) - divê em nirxa hatî li ya berê zêde bikin.
- Bi xalek taybetî (bilind, nizm, ..) - nirxa yekem di hûrdemê de ji daneyên gihîştî tê girtin, yên mayî bi karanîna fonksiyonê têne hesibandin.
- Rehetî. Her tim bi karanîna fonksiyonek tê hesibandin.
Ka em guhêrbaran ji bo van çînan diyar bikin:
accumulatorCols:`numTrades`volume`pvolume`turnover;
specialCols:`high`low`firstPrice`firstSize;
Fermana hesabkirinê
Em ê tabloya berhevkirî di du qonaxan de nûve bikin. Ji bo bikêrhatîbûnê, em pêşî tabloya hatinê piçûk dikin da ku ji bo her karakter û hûrdem tenê rêzek hebe. Rastiya ku hemî fonksiyonên me zêdebûn û hevgirtî ne, garantî dike ku encama vê gavê zêde nayê guhertin. Hûn dikarin tabloyê bi karanîna hilbijarkek piçûk bikin:
select high:max price, low:min price … by sym,time.minute from table
Vê rêbazê dezavantajek heye - komek stûnên hesabkirî ji berê ve hatî destnîşan kirin. Xweşbextane, di Q de, hilbijartî jî wekî fonksiyonek tête bicîh kirin ku hûn dikarin argûmanên dînamîkî yên hatine afirandin biguhezînin:
?[table;whereClause;byClause;selectClause]
Ez ê di halê me de forma argumanan bi hûrgulî venabêjim, tenê ji hêla bêjeyan ve û bijartî dê nebingehîn bin û divê ew bibin ferhengên stûnên formê! Ji ber vê yekê, fonksiyona piçûkkirinê dikare wekî jêrîn were destnîşankirin:
selExpression:`high`low`firstPrice`lastPrice`firstSize`lastSize`numTrades`volume`pvolume`turnover!parse each ("max price";"min price";"first price";"last price";"first size";"last size";"count i";"sum size";"sum price";"sum price*size"); // each это функция map в Q для одного списка
preprocess:?[;();`sym`time!`sym`time.minute;selExpression];
Ji bo zelaliyê, min fonksiyona parsek bikar anî, ya ku rêzek bi bêjeyek Q veguherîne nirxek ku dikare ji fonksiyona eval re were derbas kirin û ya ku di hilbijarka fonksiyonê de hewce ye. Di heman demê de bala xwe bidin ku pêvajo wekî projeyek (ango fonksiyonek bi argumanên qismî diyarkirî) ya fonksiyona hilbijartî tê pênase kirin, yek arguman (tablo) winda ye. Ger em pêvajoyek pêşîn li tabloyek bicîh bînin, em ê tabloyek pêçandî bistînin.
Qonaxa duyemîn nûvekirina tabloya hevgirtî ye. Ka em pêşî algorîtmayê bi pseudokodê binivîsin:
for each sym in inputTable
idx: row index in agg table for sym+currentTime;
aggTable[idx;`high]: aggTable[idx;`high] | inputTable[sym;`high];
aggTable[idx;`volume]: aggTable[idx;`volume] + inputTable[sym;`volume];
…
Di Q de, bi gelemperî li şûna xelekên nexşeyê/kêmkirina fonksiyonan tê bikar anîn. Lê ji ber ku Q zimanek vektor e û em dikarin bi hêsanî hemî operasyonan bi yekcarî li ser hemî sembolan bicîh bikin, wê hingê em dikarin hema hema hema hema hema hema bêyî lûkê bikin, li ser hemî sembolan bi yekcarî operasyonan bikin:
idx:calcIdx inputTable;
row:aggTable idx;
aggTable[idx;`high]: row[`high] | inputTable`high;
aggTable[idx;`volume]: row[`volume] + inputTable`volume;
…
Lê em dikarin pêşdetir biçin, Q operatorek yekta û zehf bi hêz heye - operatorê peywira giştî. Ew dihêle hûn bi karanîna navnîşek nîşanan, fonksiyon û argûmanan di avahiyek daneya tevlihev de komek nirxan biguhezînin. Di rewşa me de ev xuya dike:
idx:calcIdx inputTable;
rows:aggTable idx;
// .[target;(idx0;idx1;..);function;argument] ~ target[idx 0;idx 1;…]: function[target[idx 0;idx 1;…];argument], в нашем случае функция – это присваивание
.[aggTable;(idx;aggCols);:;flip (row[`high] | inputTable`high;row[`volume] + inputTable`volume;…)];
Mixabin, ji bo veqetandina tabloyek hûn hewceyê navnîşek rêzan, ne stûnan, û hûn neçar in ku matrixê (lîsteya stûnan li navnîşa rêzikan) bi karanîna fonksiyona flip veguherînin. Ev ji bo tabloyek mezin biha ye, ji ber vê yekê em li ser her stûnê ji hev veqetandî peywirek gelemperî bicîh dikin, fonksiyona nexşeyê (ya ku wekî apostrofek xuya dike) bikar tînin:
.[aggTable;;:;]'[(idx;)each aggCols; (row[`high] | inputTable`high;row[`volume] + inputTable`volume;…)];
Em dîsa projekirina fonksiyonê bikar tînin. Di heman demê de bala xwe bidin ku di Q de, çêkirina navnîşek jî fonksiyonek e û em dikarin bi karanîna fonksiyona her (nexşeyê) jê re bang bikin da ku navnîşek navnîşan bistînin.
Ji bo ku bicîh bikin ku komek stûnên hesabkirî ne sabît e, em ê biwêja jorîn bi dînamîk biafirînin. Werin em pêşî fonksiyonan diyar bikin da ku her stûnek hesab bikin, guhêrbarên rêz û inp bikar bînin da ku li daneyên berhevkirî û têketinê binihêrin:
aggExpression:`high`low`firstPrice`lastPrice`firstSize`lastSize`avgPrice`avgSize`vwap`cumVolume!
("row[`high]|inp`high";"row[`low]&inp`low";"row`firstPrice";"inp`lastPrice";"row`firstSize";"inp`lastSize";"pvolume%numTrades";"volume%numTrades";"turnover%volume";"row[`cumVolume]+inp`volume");
Hin stûnên taybetî ne, divê nirxa wan a yekem ji hêla fonksiyonê ve neyê hesibandin. Em dikarin diyar bikin ku ew ji hêla rêza[`numTrades] stûna yekem e - heke 0 hebe, wê hingê nirx yekem e. Q fonksiyonek hilbijartî heye - ?[Lîsteya Boolean; list1;lîsteya2] - ku li gorî şertê di argumana yekem de nirxek ji navnîşa 1 an 2 hildibijêre:
// high -> ?[isFirst;inp`high;row[`high]|inp`high]
// @ - тоже обобщенное присваивание для случая когда индекс неглубокий
@[`aggExpression;specialCols;{[x;y]"?[isFirst;inp`",y,";",x,"]"};string specialCols];
Li vir min bi fonksiyona xwe re gazî peywirek giştîkirî kir (îfadekirinek di birûskên kelandî de). Ew nirxa heyî (argumana yekem) û argumanek zêde distîne, ku ez di parametreya 4-an de derbas dikim.
Ka em axaftvanên bateriyê ji hev cuda lê zêde bikin, ji ber ku fonksiyon ji wan re yek e:
// volume -> row[`volume]+inp`volume
aggExpression[accumulatorCols]:{"row[`",x,"]+inp`",x } each string accumulatorCols;
Ev ji hêla standardên Q ve peywirek normal e, lê ez yekcar navnîşek nirxan destnîşan dikim. Di dawiyê de, em fonksiyona sereke biafirînin:
// ":",/:aggExprs ~ map[{":",x};aggExpr] => ":row[`high]|inp`high" присвоим вычисленное значение переменной, потому что некоторые колонки зависят от уже вычисленных значений
// string[cols],'exprs ~ map[,;string[cols];exprs] => "high:row[`high]|inp`high" завершим создание присваивания. ,’ расшифровывается как map[concat]
// ";" sv exprs – String from Vector (sv), соединяет список строк вставляя “;” посредине
updateAgg:value "{[aggTable;idx;inp] row:aggTable idx; isFirst_0=row`numTrades; .[aggTable;;:;]'[(idx;)each aggCols;(",(";"sv string[aggCols],'":",/:aggExpression aggCols),")]}";
Bi vê îfadeyê, ez bi dînamîk fonksiyonek ji rêzek ku tê de îfadeya ku min li jor daye diafirînim. Encam dê wiha xuya bike:
{[aggTable;idx;inp] rows:aggTable idx; isFirst_0=row`numTrades; .[aggTable;;:;]'[(idx;)each aggCols ;(cumVolume:row[`cumVolume]+inp`cumVolume;… ; high:?[isFirst;inp`high;row[`high]|inp`high])]}
Rêza nirxandina stûnê berevajî ye ji ber ku di Q de rêza nirxandinê ji rastê ber bi çepê ve ye.
Naha du fonksiyonên me yên sereke hene ku ji bo hesaban hewce ne, em tenê hewce ne ku binesaziyek piçûk lê zêde bikin û karûbar amade ye.
gavên dawî
Me fonksiyonên pêşdibistanê û nûvekirinaAgg hene ku hemî karan dikin. Lê dîsa jî pêdivî ye ku meriv bi hûrgulî veguheztina rast were piştrast kirin û ji bo berhevkirinê indexan hesab bike. Berî her tiştî, em fonksiyona destpêkê diyar bikin:
init:{
tradeAgg:: 0#enlist[initWith]; // создаем пустую типизированную таблицу, enlist превращает словарь в таблицу, а 0# означает взять 0 элементов из нее
currTime::00:00; // начнем с 0, :: означает, что присваивание в глобальную переменную
currSyms::`u#`symbol$(); // `u# - превращает список в дерево, для ускорения поиска элементов
offset::0; // индекс в tradeAgg, где начинается текущая минута
rollCache:: `sym xkey update `u#sym from rollColumns#tradeAgg; // кэш для последних значений roll колонок, таблица с ключом sym
}
Em ê di heman demê de fonksiyona roll diyar bikin, ku dê hûrdema heyî biguhezîne:
roll:{[tm]
if[currTime>tm; :init[]]; // если перевалили за полночь, то просто вызовем init
rollCache,::offset _ rollColumns#tradeAgg; // обновим кэш – взять roll колонки из aggTable, обрезать, вставить в rollCache
offset::count tradeAgg;
currSyms::`u#`$();
}
Em ê fonksiyonek hewce bikin ku karakterên nû lê zêde bikin:
addSyms:{[syms]
currSyms,::syms; // добавим в список известных
// добавим в таблицу sym, time и rollColumns воспользовавшись обобщенным присваиванием.
// Функция ^ подставляет значения по умолчанию для roll колонок, если символа нет в кэше. value flip table возвращает список колонок в таблице.
`tradeAgg upsert @[count[syms]#enlist initWith;`sym`time,cols rc;:;(syms;currTime), (initWith cols rc)^value flip rc:rollCache ([] sym: syms)];
}
Û di dawiyê de, fonksiyona nûvekirinê (navê kevneşopî ya vê fonksiyonê ji bo karûbarên Q), ku ji hêla xerîdar ve tê gazî kirin da ku daneyan zêde bike:
upd:{[tblName;data] // tblName нам не нужно, но обычно сервис обрабатывает несколько таблиц
tm:exec distinct time from data:() xkey preprocess data; // preprocess & calc time
updMinute[data] each tm; // добавим данные для каждой минуты
};
updMinute:{[data;tm]
if[tm<>currTime; roll tm; currTime::tm]; // поменяем минуту, если необходимо
data:select from data where time=tm; // фильтрация
if[count msyms:syms where not (syms:data`sym)in currSyms; addSyms msyms]; // новые символы
updateAgg[`tradeAgg;offset+currSyms?syms;data]; // обновим агрегированную таблицу. Функция ? ищет индекс элементов списка справа в списке слева.
};
Navê pêger. Li vir koda bêkêmasî ya karûbarê me ye, wekî ku soz daye, tenê çend rêz:
initWith:`sym`time`high`low`firstPrice`lastPrice`firstSize`lastSize`numTrades`volume`pvolume`turnover`avgPrice`avgSize`vwap`cumVolume!(`;00:00;0n;0n;0n;0n;0N;0N;0;0;0.0;0.0;0n;0n;0n;0);
aggCols:reverse key[initWith] except `sym`time;
rollColumns:`sym`cumVolume;
accumulatorCols:`numTrades`volume`pvolume`turnover;
specialCols:`high`low`firstPrice`firstSize;
selExpression:`high`low`firstPrice`lastPrice`firstSize`lastSize`numTrades`volume`pvolume`turnover!parse each ("max price";"min price";"first price";"last price";"first size";"last size";"count i";"sum size";"sum price";"sum price*size");
preprocess:?[;();`sym`time!`sym`time.minute;selExpression];
aggExpression:`high`low`firstPrice`lastPrice`firstSize`lastSize`avgPrice`avgSize`vwap`cumVolume!("row[`high]|inp`high";"row[`low]&inp`low";"row`firstPrice";"inp`lastPrice";"row`firstSize";"inp`lastSize";"pvolume%numTrades";"volume%numTrades";"turnover%volume";"row[`cumVolume]+inp`volume");
@[`aggExpression;specialCols;{"?[isFirst;inp`",y,";",x,"]"};string specialCols];
aggExpression[accumulatorCols]:{"row[`",x,"]+inp`",x } each string accumulatorCols;
updateAgg:value "{[aggTable;idx;inp] row:aggTable idx; isFirst_0=row`numTrades; .[aggTable;;:;]'[(idx;)each aggCols;(",(";"sv string[aggCols],'":",/:aggExpression aggCols),")]}"; / '
init:{
tradeAgg::0#enlist[initWith];
currTime::00:00;
currSyms::`u#`symbol$();
offset::0;
rollCache:: `sym xkey update `u#sym from rollColumns#tradeAgg;
};
roll:{[tm]
if[currTime>tm; :init[]];
rollCache,::offset _ rollColumns#tradeAgg;
offset::count tradeAgg;
currSyms::`u#`$();
};
addSyms:{[syms]
currSyms,::syms;
`tradeAgg upsert @[count[syms]#enlist initWith;`sym`time,cols rc;:;(syms;currTime),(initWith cols rc)^value flip rc:rollCache ([] sym: syms)];
};
upd:{[tblName;data] updMinute[data] each exec distinct time from data:() xkey preprocess data};
updMinute:{[data;tm]
if[tm<>currTime; roll tm; currTime::tm];
data:select from data where time=tm;
if[count msyms:syms where not (syms:data`sym)in currSyms; addSyms msyms];
updateAgg[`tradeAgg;offset+currSyms?syms;data];
};
Îmtîhanê
Werin em performansa karûbarê kontrol bikin. Ji bo vê yekê, em wê di pêvajoyek cûda de bimeşînin (kodê têxin pelê service.q) û fonksiyona destpêkê bang bikin:
q service.q –p 5566
q)init[]
Di konsolek din de, pêvajoya Q duyemîn dest pê bikin û bi ya yekem ve girêdin:
h:hopen `:host:5566
h:hopen 5566 // если оба на одном хосте
Pêşîn, em navnîşek sembolan çêbikin - 10000 perçe û fonksiyonek lê zêde bikin da ku tabloyek rasthatî biafirînin. Di konsolê duyemîn de:
syms:`IBM`AAPL`GOOG,-9997?`8
rnd:{[n;t] ([] sym:n?syms; time:t+asc n#til 25; price:n?10f; size:n?10)}
Min sê sembolên rastîn li navnîşê zêde kir da ku ez hêsantir li wan di tabloyê de bigerim. Fonksiyona rnd bi n rêzan tabloyek bêserûber diafirîne, ku dem ji t heta t+25 milîsaniyeyan diguhere.
Naha hûn dikarin biceribînin ku daneyan ji karûbarê re bişînin (deh demjimêrên pêşîn zêde bikin):
{h (`upd;`trade;rnd[10000;x])} each `time$00:00 + til 60*10
Hûn dikarin di karûbarê de kontrol bikin ku tablo hatî nûve kirin:
c 25 200
select from tradeAgg where sym=`AAPL
-20#select from tradeAgg where sym=`AAPL
Encam:
sym|time|high|low|firstPrice|lastPrice|firstSize|lastSize|numTrades|volume|pvolume|turnover|avgPrice|avgSize|vwap|cumVolume
--|--|--|--|--|--------------------------------
AAPL|09:27|9.258904|9.258904|9.258904|9.258904|8|8|1|8|9.258904|74.07123|9.258904|8|9.258904|2888
AAPL|09:28|9.068162|9.068162|9.068162|9.068162|7|7|1|7|9.068162|63.47713|9.068162|7|9.068162|2895
AAPL|09:31|4.680449|0.2011121|1.620827|0.2011121|1|5|4|14|9.569556|36.84342|2.392389|3.5|2.631673|2909
AAPL|09:33|2.812535|2.812535|2.812535|2.812535|6|6|1|6|2.812535|16.87521|2.812535|6|2.812535|2915
AAPL|09:34|5.099025|5.099025|5.099025|5.099025|4|4|1|4|5.099025|20.3961|5.099025|4|5.099025|2919Werin em naha ceribandina barkirinê bikin da ku fêr bibin ka karûbar dikare di hûrdemê de çiqas daneyê pêvajoyê bike. Bihêle ku ez ji we re bi bîr bînim ku me navberê nûvekirinê li 25 milî çirkeyan destnîşan kir. Li gorî vê yekê, pêdivî ye ku karûbar (bi navînî) bi kêmî ve 20 milî çirkeyan di her nûvekirinê de cih bigire da ku dem bide bikarhêneran da ku daneyan daxwaz bikin. Di pêvajoya duyemîn de jêrîn binivîse:
tm:10:00:00.000
stressTest:{[n] 1 string[tm]," "; times,::h ({st:.z.T; upd[`trade;x]; .z.T-st};rnd[n;tm]); tm+:25}
start:{[n] times::(); do[4800;stressTest[n]]; -1 " "; `min`avg`med`max!(min times;avg times;med times;max times)}
4800 du deqe ye. Hûn dikarin pêşî biceribînin ku her 1000 milîçirkeyan 25 rêzan bimeşînin:
start 1000
Di doza min de, encam ji her nûvekirinê dora çend milî çirkeyan e. Ji ber vê yekê ez ê tavilê hejmara rêzan zêde bikim 10.000:
start 10000
Encam:
min| 00:00:00.004
avg| 9.191458
med| 9f
max| 00:00:00.030
Dîsa, tiştek taybetî ye, lê ev 24 mîlyon xet di hûrdemê de, 400 hezar di çirkeyê de. Zêdetirî 25 milî çirkeyan, nûvekirin tenê 5 carî hêdî bû, xuya ye dema ku hûrdem guherî. Ka em bibin 100.000:
start 100000
Encam:
min| 00:00:00.013
avg| 25.11083
med| 24f
max| 00:00:00.108
q)sum times
00:02:00.532
Wekî ku hûn dikarin bibînin, karûbar bi zor dikare bi ser keve, lê di heman demê de ew kar dike ku li ser piyan bimîne. Hêjmarek daneya wusa (240 mîlyon rêz di hûrdeman de) di rewşên weha de pir mezin e, gelemperî ye ku meriv çend klonan (an jî bi dehan klone) karûbarê dest pê bike, ku her yek ji wan tenê beşek ji karakteran pêvajoyê dike. Dîsa jî, encam ji bo zimanek şirovekirî ku di serî de balê dikişîne ser hilanîna daneyê balkêş e.
Dibe ku pirs derkeve holê ka çima dem bi mezinahiya her nûvekirinê re ne-xêzik mezin dibe. Sedem ev e ku fonksiyona piçûkkirinê bi rastî fonksiyonek C ye, ku ji updateAgg pir bikêrtir e. Ji nûvekirinek diyarkirî (nêzîkî 10.000) dest pê dike, updateAgg digihîje asta xwe û dûv re dema darvekirina wê bi mezinahiya nûvekirinê ve girêdayî nabe. Ew ji ber gava pêşîn Q ye ku karûbar karibe jimareyên weha daneyan bişewitîne. Ev ronî dike ka çiqas girîng e ku meriv algorîtmaya rast hilbijêrin dema ku bi daneyên mezin re dixebitin. Xalek din hilanîna rast a daneyan di bîranînê de ye. Ger dane bi stûnek nehatibûna hilanîn an jî bi demê re nehatibin ferman kirin, wê hingê em ê bi tiştek wekî wendakirina cache TLB-nebûna navnîşek rûpela bîranînê di cacheya navnîşana pêvajoyê de nas bikin. Lêgerîna navnîşanek heke neserkeve bi qasî 30 carî dirêjtir digire, û heke dane belav be, ew dikare karûbarê çend caran hêdî bike.
encamê
Di vê gotarê de, min destnîşan kir ku databasa KDB+ û Q ne tenê ji bo hilanîna daneyên mezin û bi hêsanî gihîştina wan bi hilbijartî re maqûl e, lê di heman demê de ji bo afirandina karûbarên hilberandina daneyê ku karibe bi sedan mîlyon rêz / gigabyte daneyan jî di nav de bihejîne. yek Q pêvajoya yek. Zimanê Q bixwe ji ber cewhera xweya vektorî, wergêrê zaravaya SQL-ya çêkirî û komek fonksiyonên pirtûkxaneyê ya pir serfiraz a algorîtmayên ku bi hilberandina daneyê ve girêdayî ne, pir kurt û bikêrhatî dihêle.
Ez ê bala xwe bidim ku ya jorîn tenê beşek ji tiştê ku Q dikare bike ye, ew taybetmendiyên din ên bêhempa jî hene. Mînakî, protokolek IPC ya pir sade ku sînorê di navbera pêvajoyên Q kesane de radike û dihêle hûn bi sedan van pêvajoyan di nav torek yekane de, ku dikare li ser bi dehan serverên li deverên cihêreng ên cîhanê were bicîh kirin, bicivîne.
Source: www.habr.com
