DBMS gnìomhach

Tha saoghal nan stòran-dàta air a bhith fo smachd o chionn fhada le DBMSan dàimheach, a bhios a’ cleachdadh cànan SQL. Na h-uimhir gus an canar NoSQL ri caochlaidhean a tha a’ tighinn am bàrr. Chaidh aca air àite sònraichte a shnaigheadh ​​​​a-mach dhaibh fhèin sa mhargaidh seo, ach chan eil DBMSan dàimheach gu bhith a’ bàsachadh, agus tha iad fhathast gan cleachdadh gu gnìomhach airson an adhbharan.

San artaigil seo tha mi airson cunntas a thoirt air bun-bheachd stòr-dàta gnìomh. Airson tuigse nas fheàrr, nì mi seo le bhith ga choimeas ris a’ mhodail dhàimheach clasaigeach. Thèid duilgheadasan bho dhiofar dheuchainnean SQL a lorgar air an eadar-lìn a chleachdadh mar eisimpleirean.

Ro-ràdh

Bidh stòran-dàta càirdeach ag obrachadh air clàran agus raointean. Ann an stòr-dàta gnìomh, thèid clasaichean agus gnìomhan a chleachdadh nan àite, fa leth. Bidh raon ann an clàr le iuchraichean N air a riochdachadh mar dhleastanas air paramadairean N. An àite dàimhean eadar bùird, thèid gnìomhan a chleachdadh a thilleas nithean den chlas ris a bheil an ceangal air a dhèanamh. Thèid sgrìobhadh gnìomh a chleachdadh an àite JOIN.

Mus gluais thu gu dìreach gu na gnìomhan, bheir mi cunntas air gnìomh loidsig fearainn. Airson DDL cleachdaidh mi co-chòrdadh PostgreSQL. Airson gnìomh tha a cho-chòrdadh fhèin aige.

Clàran agus raointean

Rud Sku sìmplidh le raointean ainm is prìsean:

Dàimheach

CREATE TABLE Sku
(
    id bigint NOT NULL,
    name character varying(100),
    price numeric(10,5),
    CONSTRAINT id_pkey PRIMARY KEY (id)
)

Gnìomh

CLASS Sku;
name = DATA STRING[100] (Sku);
price = DATA NUMERIC[10,5] (Sku);

Bidh sinn ag ainmeachadh dhà gnìomhan, a bheir aon paramadair Sku mar chur-a-steach agus a 'tilleadh seòrsa prìomhadail.

Thathas a’ gabhail ris gum bi còd a-staigh aig gach nì ann an DBMS gnìomh a thèid a chruthachadh gu fèin-ghluasadach agus a gheibhear thuige ma tha sin riatanach.

Nach suidhich sinn a’ phrìs airson an toradh/stòr/solaraiche. Dh’ fhaodadh e atharrachadh thar ùine, mar sin leig dhuinn raon ùine a chur ris a’ chlàr. Bidh mi a’ sgioblachadh clàran airson clàran ann an stòr-dàta dàimheach gus an còd a ghiorrachadh:

Dàimheach

CREATE TABLE prices
(
    skuId bigint NOT NULL,
    storeId bigint NOT NULL,
    supplierId bigint NOT NULL,
    dateTime timestamp without time zone,
    price numeric(10,5),
    CONSTRAINT prices_pkey PRIMARY KEY (skuId, storeId, supplierId)
)

Gnìomh

CLASS Sku;
CLASS Store;
CLASS Supplier;
dateTime = DATA DATETIME (Sku, Store, Supplier);
price = DATA NUMERIC[10,5] (Sku, Store, Supplier);

Clàran-innse

Airson an eisimpleir mu dheireadh, togaidh sinn clàr-amais air a h-uile iuchair agus an ceann-latha gus an lorg sinn gu luath am prìs airson ùine shònraichte.

Dàimheach

CREATE INDEX prices_date
    ON prices
    (skuId, storeId, supplierId, dateTime)

Gnìomh

INDEX Sku sk, Store st, Supplier sp, dateTime(sk, st, sp);

gnìomhan

Feuch an tòisich sinn le duilgheadasan an ìre mhath sìmplidh air an toirt bhon cho-fhreagarrach artaigilean air Habr.

An toiseach, leig dhuinn loidsig an àrainn ainmeachadh (airson an stòr-dàta dàimheach tha seo air a dhèanamh gu dìreach san artaigil gu h-àrd).

CLASS Department;
name = DATA STRING[100] (Department);

CLASS Employee;
department = DATA Department (Employee);
chief = DATA Employee (Employee);
name = DATA STRING[100] (Employee);
salary = DATA NUMERIC[14,2] (Employee);

Tasg 1.1

Seall liosta de luchd-obrach a gheibh tuarastal nas àirde na an neach-stiùiridh aca.

Dàimheach

select a.*
from   employee a, employee b
where  b.id = a.chief_id
and    a.salary > b.salary

Gnìomh

SELECT name(Employee a) WHERE salary(a) > salary(chief(a));

Tasg 1.2

Dèan liosta den luchd-obrach a gheibh an tuarastal as àirde san roinn aca

Dàimheach

select a.*
from   employee a
where  a.salary = ( select max(salary) from employee b
                    where  b.department_id = a.department_id )

Gnìomh

maxSalary 'Максимальная зарплата' (Department s) = 
    GROUP MAX salary(Employee e) IF department(e) = s;
SELECT name(Employee a) WHERE salary(a) = maxSalary(department(a));

// или если "заинлайнить"
SELECT name(Employee a) WHERE 
    salary(a) = maxSalary(GROUP MAX salary(Employee e) IF department(e) = department(a));

Tha an dà bhuileachadh co-ionann. Airson a 'chiad chùis, ann an stòr-dàta dàimh faodaidh tu CREATE VIEW a chleachdadh, a bhios san aon dòigh a' obrachadh a-mach an tuarastal as àirde airson roinn shònraichte ann. Anns na leanas, airson soilleireachd, cleachdaidh mi a 'chiad chùis, oir tha e nas fheàrr a' nochdadh an fhuasglaidh.

Tasg 1.3

Taisbeanaidh liosta de IDan roinne, an àireamh de luchd-obrach anns nach eil barrachd air 3 neach.

Dàimheach

select department_id
from   employee
group  by department_id
having count(*) <= 3

Gnìomh

countEmployees 'Количество сотрудников' (Department d) = 
    GROUP SUM 1 IF department(Employee e) = d;
SELECT Department d WHERE countEmployees(d) <= 3;

Tasg 1.4

Seall liosta de luchd-obrach aig nach eil manaidsear ainmichte ag obair san aon roinn.

Dàimheach

select a.*
from   employee a
left   join employee b on (b.id = a.chief_id and b.department_id = a.department_id)
where  b.id is null

Gnìomh

SELECT name(Employee a) WHERE NOT (department(chief(a)) = department(a));

Tasg 1.5

Lorg liosta de IDan roinnean leis an tuarastal iomlan luchd-obrach as àirde.

Dàimheach

with sum_salary as
  ( select department_id, sum(salary) salary
    from   employee
    group  by department_id )
select department_id
from   sum_salary a       
where  a.salary = ( select max(salary) from sum_salary )

Gnìomh

salarySum 'Максимальная зарплата' (Department d) = 
    GROUP SUM salary(Employee e) IF department(e) = d;
maxSalarySum 'Максимальная зарплата отделов' () = 
    GROUP MAX salarySum(Department d);
SELECT Department d WHERE salarySum(d) = maxSalarySum();

Gluaisidh sinn air adhart gu gnìomhan nas iom-fhillte bho neach eile artaigilean. Tha mion-sgrùdadh mionaideach ann air mar a chuireas tu an gnìomh seo an gnìomh ann an MS SQL.

Tasg 2.1

Dè an luchd-reic a reic còrr is 1997 aonad de bhathar Àir. 30 ann an 1?

Loidsig fearainn (mar a bha roimhe air RDBMS bidh sinn a’ leum air an dearbhadh):

CLASS Employee 'Продавец';
lastName 'Фамилия' = DATA STRING[100] (Employee);

CLASS Product 'Продукт';
id = DATA INTEGER (Product);
name = DATA STRING[100] (Product);

CLASS Order 'Заказ';
date = DATA DATE (Order);
employee = DATA Employee (Order);

CLASS Detail 'Строка заказа';

order = DATA Order (Detail);
product = DATA Product (Detail);
quantity = DATA NUMERIC[10,5] (Detail);

Dàimheach

select LastName
from Employees as e
where (
  select sum(od.Quantity)
  from [Order Details] as od
  where od.ProductID = 1 and od.OrderID in (
    select o.OrderID
    from Orders as o
    where year(o.OrderDate) = 1997 and e.EmployeeID = o.EmployeeID)
) > 30

Gnìomh

sold (Employee e, INTEGER productId, INTEGER year) = 
    GROUP SUM quantity(OrderDetail d) IF 
        employee(order(d)) = e AND 
        id(product(d)) = productId AND 
        extractYear(date(order(d))) = year;
SELECT lastName(Employee e) WHERE sold(e, 1, 1997) > 30;

Tasg 2.2

Airson gach ceannaiche (ainm, sloinneadh), lorg an dà bhathar (ainm) air an do chuir an ceannaiche seachad an airgead as motha ann an 1997.

Bidh sinn a’ leudachadh loidsig na h-àrainn bhon eisimpleir roimhe:

CLASS Customer 'Клиент';
contactName 'ФИО' = DATA STRING[100] (Customer);

customer = DATA Customer (Order);

unitPrice = DATA NUMERIC[14,2] (Detail);
discount = DATA NUMERIC[6,2] (Detail);

Dàimheach

SELECT ContactName, ProductName FROM (
SELECT c.ContactName, p.ProductName
, ROW_NUMBER() OVER (
    PARTITION BY c.ContactName
    ORDER BY SUM(od.Quantity * od.UnitPrice * (1 - od.Discount)) DESC
) AS RatingByAmt
FROM Customers c
JOIN Orders o ON o.CustomerID = c.CustomerID
JOIN [Order Details] od ON od.OrderID = o.OrderID
JOIN Products p ON p.ProductID = od.ProductID
WHERE YEAR(o.OrderDate) = 1997
GROUP BY c.ContactName, p.ProductName
) t
WHERE RatingByAmt < 3

Gnìomh

sum (Detail d) = quantity(d) * unitPrice(d) * (1 - discount(d));
bought 'Купил' (Customer c, Product p, INTEGER y) = 
    GROUP SUM sum(Detail d) IF 
        customer(order(d)) = c AND 
        product(d) = p AND 
        extractYear(date(order(d))) = y;
rating 'Рейтинг' (Customer c, Product p, INTEGER y) = 
    PARTITION SUM 1 ORDER DESC bought(c, p, y), p BY c, y;
SELECT contactName(Customer c), name(Product p) WHERE rating(c, p, 1997) < 3;

Bidh an gnìomhaiche PÀIRT ag obair air a’ phrionnsapal a leanas: bidh e a’ toirt cunntas air an abairt a chaidh a shònrachadh às deidh SUM (an seo 1), taobh a-staigh nam buidhnean ainmichte (an seo Luchd-ceannach agus Bliadhna, ach dh’ fhaodadh gur e abairt sam bith a th ’ann), a’ rèiteachadh taobh a-staigh nam buidhnean a rèir na h-abairtean a tha air an sònrachadh san ORDER ( an seo air a cheannach, agus ma tha e co-ionann, an uairsin a rèir a’ chòd toraidh a-staigh).

Tasg 2.3

Cia mheud bathar a dh’ fheumar òrdachadh bho sholaraichean gus òrdughan gnàthach a choileanadh.

Leudaichidh sinn loidsig na h-àrainn a-rithist:

CLASS Supplier 'Поставщик';
companyName = DATA STRING[100] (Supplier);

supplier = DATA Supplier (Product);

unitsInStock 'Остаток на складе' = DATA NUMERIC[10,3] (Product);
reorderLevel 'Норма продажи' = DATA NUMERIC[10,3] (Product);

Dàimheach

select s.CompanyName, p.ProductName, sum(od.Quantity) + p.ReorderLevel — p.UnitsInStock as ToOrder
from Orders o
join [Order Details] od on o.OrderID = od.OrderID
join Products p on od.ProductID = p.ProductID
join Suppliers s on p.SupplierID = s.SupplierID
where o.ShippedDate is null
group by s.CompanyName, p.ProductName, p.UnitsInStock, p.ReorderLevel
having p.UnitsInStock < sum(od.Quantity) + p.ReorderLevel

Gnìomh

orderedNotShipped 'Заказано, но не отгружено' (Product p) = 
    GROUP SUM quantity(OrderDetail d) IF product(d) = p;
toOrder 'К заказу' (Product p) = orderedNotShipped(p) + reorderLevel(p) - unitsInStock(p);
SELECT companyName(supplier(Product p)), name(p), toOrder(p) WHERE toOrder(p) > 0;

Trioblaid le rionnag

Agus tha an eisimpleir mu dheireadh bhuam gu pearsanta. Tha loidsig lìonra sòisealta ann. Faodaidh daoine a bhith nan caraidean dha chèile agus coltach ri chèile. Bho shealladh stòr-dàta gnìomh bhiodh e a’ coimhead mar seo:

CLASS Person;
likes = DATA BOOLEAN (Person, Person);
friends = DATA BOOLEAN (Person, Person);

Tha e riatanach tagraichean a lorg airson càirdeas. Nas foirmeile, feumaidh tu a h-uile duine A, B, C a lorg gus am bi A na charaidean le B, agus B na charaidean le C, is toil le A C, ach chan eil A na charaidean le C.
Bho shealladh stòr-dàta gnìomh, bhiodh a’ cheist a’ coimhead mar seo:

SELECT Person a, Person b, Person c WHERE 
    likes(a, c) AND NOT friends(a, c) AND 
    friends(a, b) AND friends(b, c);

Tha an leughadair air a bhrosnachadh gus an duilgheadas seo fhuasgladh ann an SQL leis fhèin. Thathas a’ gabhail ris gu bheil tòrr nas lugha de charaidean ann na tha daoine a’ còrdadh riut. Mar sin tha iad ann an clàran fa leth. Ma tha e soirbheachail, tha gnìomh ann cuideachd le dà rionnag. Ann an sin, chan eil càirdeas co-chothromach. Air stòr-dàta gnìomh bhiodh e a’ coimhead mar seo:

SELECT Person a, Person b, Person c WHERE 
    likes(a, c) AND NOT friends(a, c) AND 
    (friends(a, b) OR friends(b, a)) AND 
    (friends(b, c) OR friends(c, b));

UPD: fuasgladh air an duilgheadas leis a’ chiad agus an dàrna rionnag bho dss_calika:

SELECT 
   pl.PersonAID
  ,pf.PersonAID
  ,pff.PersonAID
FROM Persons                 AS p
--Лайки                      
JOIN PersonRelationShip      AS pl ON pl.PersonAID = p.PersonID
                                  AND pl.Relation  = 'Like'
--Друзья                     
JOIN PersonRelationShip      AS pf ON pf.PersonAID = p.PersonID 
                                  AND pf.Relation = 'Friend'
--Друзья Друзей              
JOIN PersonRelationShip      AS pff ON pff.PersonAID = pf.PersonBID
                                   AND pff.PersonBID = pl.PersonBID
                                   AND pff.Relation = 'Friend'
--Ещё не дружат         
LEFT JOIN PersonRelationShip AS pnf ON pnf.PersonAID = p.PersonID
                                   AND pnf.PersonBID = pff.PersonBID
                                   AND pnf.Relation = 'Friend'
WHERE pnf.PersonAID IS NULL 

;WITH PersonRelationShipCollapsed AS (
  SELECT pl.PersonAID
        ,pl.PersonBID
        ,pl.Relation 
  FROM #PersonRelationShip      AS pl 
  
  UNION 

  SELECT pl.PersonBID AS PersonAID
        ,pl.PersonAID AS PersonBID
        ,pl.Relation
  FROM #PersonRelationShip      AS pl 
)
SELECT 
   pl.PersonAID
  ,pf.PersonBID
  ,pff.PersonBID
FROM #Persons                      AS p
--Лайки                      
JOIN PersonRelationShipCollapsed  AS pl ON pl.PersonAID = p.PersonID
                                 AND pl.Relation  = 'Like'                                  
--Друзья                          
JOIN PersonRelationShipCollapsed  AS pf ON pf.PersonAID = p.PersonID 
                                 AND pf.Relation = 'Friend'
--Друзья Друзей                   
JOIN PersonRelationShipCollapsed  AS pff ON pff.PersonAID = pf.PersonBID
                                 AND pff.PersonBID = pl.PersonBID
                                 AND pff.Relation = 'Friend'
--Ещё не дружат                   
LEFT JOIN PersonRelationShipCollapsed AS pnf ON pnf.PersonAID = p.PersonID
                                   AND pnf.PersonBID = pff.PersonBID
                                   AND pnf.Relation = 'Friend'
WHERE pnf.[PersonAID] IS NULL 

co-dhùnadh

Bu chòir a thoirt fa-near gur e an co-chòrdadh cànain a chaidh a thoirt seachad dìreach aon de na roghainnean airson a’ bhun-bheachd a chaidh a thoirt seachad a bhuileachadh. Chaidh SQL a ghabhail mar bhunait, agus b 'e an t-amas gum biodh e cho coltach' sa ghabhas ris. Gu dearbh, is dòcha nach toil le cuid ainmean prìomh fhaclan, clàran fhaclan, msaa. Is e am prìomh rud an seo am bun-bheachd fhèin. Ma thogras tu, faodaidh tu an dà chuid C ++ agus Python co-chòrdadh coltach ris a dhèanamh.

Tha na buannachdan a leanas aig bun-bheachd an stòr-dàta a chaidh a mhìneachadh, nam bheachd-sa:

  • faochadh. Is e comharradh caran cuspaireil a tha seo nach eil follaiseach ann an cùisean sìmplidh. Ach ma choimheadas tu air cùisean nas iom-fhillte (mar eisimpleir, duilgheadasan le reultan), an uairsin, nam bheachd-sa, tha e tòrr nas fhasa a leithid de cheistean a sgrìobhadh.
  • Инкапсуляция. Ann an cuid de dh’ eisimpleirean dh’ainmich mi gnìomhan eadar-mheadhanach (mar eisimpleir, reic, cheannaich msaa), às an deach gnìomhan a thogail às deidh sin. Leigidh seo leat loidsig gnìomhan sònraichte atharrachadh, ma tha sin riatanach, gun a bhith ag atharrachadh loidsig an fheadhainn a tha an urra riutha. Mar eisimpleir, faodaidh tu reic a dhèanamh reic air an tomhas bho nithean gu tur eadar-dhealaichte, fhad ‘s nach atharraich an còrr den loidsig. Faodaidh, faodar seo a chuir an gnìomh ann an RDBMS a’ cleachdadh CREATE VIEW. Ach ma thèid an loidsig gu lèir a sgrìobhadh san dòigh seo, cha bhith e a’ coimhead gu math furasta a leughadh.
  • Gun bheàrn semantach. Bidh stòr-dàta mar seo ag obair air gnìomhan agus clasaichean (an àite clàran agus raointean). Dìreach mar ann am prògramadh clasaigeach (ma tha sinn a 'gabhail ris gur e gnìomh a th' ann an dòigh leis a 'chiad paramadair ann an cruth a' chlas dha bheil e). Mar sin, bu chòir gum biodh e fada nas fhasa “caraidean a dhèanamh” le cànanan prògramaidh uile-choitcheann. A bharrachd air an sin, tha am bun-bheachd seo a’ ceadachadh gnìomhachd mòran nas iom-fhillte a chuir an gnìomh. Mar eisimpleir, faodaidh tu gnìomhaichean leithid:

    CONSTRAINT sold(Employee e, 1, 2019) > 100 IF name(e) = 'Петя' MESSAGE  'Что-то Петя продает слишком много одного товара в 2019 году';

  • Oighreachd agus polymorphism. Ann an stòr-dàta gnìomh, faodaidh tu iomadh oighreachd a thoirt a-steach tro CLASS ClassP: Clas 1, Clas 2 a’ togail agus a’ cur an gnìomh ioma polymorphism. Is dòcha gun sgrìobh mi cho dìreach ann an artaigilean san àm ri teachd.

Eadhon ged nach e dìreach bun-bheachd a tha seo, tha beagan buileachaidh againn mu thràth ann an Java a tha ag eadar-theangachadh a h-uile loidsig gnìomh gu loidsig dàimh. A bharrachd air an sin, tha loidsig riochdachaidhean agus tòrr rudan eile ceangailte gu breagha ris, leis am faigh sinn slàn àrd-ùrlar. Gu bunaiteach, bidh sinn a’ cleachdadh an RDBMS (PostgreSQL a-mhàin airson a-nis) mar “inneal mas-fhìor”. Bidh duilgheadasan ag èirigh uaireannan leis an eadar-theangachadh seo leis nach eil fios aig optimizer ceist RDBMS air staitistig sònraichte air a bheil an FDBMS eòlach. Ann an teòiridh, tha e comasach siostam riaghlaidh stòr-dàta a chuir an gnìomh a chleachdas structar sònraichte mar stòradh, air atharrachadh gu sònraichte airson loidsig gnìomh.

Source: www.habr.com

Cuir beachd ann