programming erlang ch17 - andstudy/forge GitHub Wiki

17์žฅ Erlang Database

ํ…Œ์ดํ„ฐ๋ฒ ์ด์Šค ์งˆ์˜

  • shop table
ํ•ญ๋ชฉ ์ˆ˜๋Ÿ‰ ๊ฐ€๊ฒฉ
apple 20 2.3
orange 100 3.8
pear 200 3.6
banana 420 4.6
potato 2456 1.2
  • cost table
์ด๋ฆ„ ๊ฐ€๊ฒฉ
apple 1.5
orange 2.4
pear 2.2
banana 1.5
potato 0.6

ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•œ ์ค€๋น„๊ณผ์ •

    1> c(test_mnesia).
    {ok,test_mnesia}
    2> test_mnesia:do_this_once().
    stopped
    
    =INFO REPORT==== 9-Aug-2008::07:42:46 ===
        application: mnesia
        exited: stopped
        type: temporary
    3> test_mnesia:start().
    ok
    4> test_mnesia:reset_tables().
    {atomic,ok}

ํ…Œ์ด๋ธ”์—์„œ ๋ชจ๋“  ๋ฐ์ดํ„ฐ ์„ ํƒํ•˜๊ธฐ

    %% SQL equivalent
    %%  SELECT * FROM shop;
    
    demo(select_shop) ->
        do(qlc:q([X || X <- mnesia:table(shop)]));

ํ…Œ์ด๋ธ”์—์„œ ๋ฐ์ดํ„ฐ ์ถ”์ถœํ•˜๊ธฐ

    %% SQL equivalent
    %%  SELECT item, quantity FROM shop;
    
    demo(select_some) ->
        do(qlc:q([{X#shop.item, X#shop.quantity} || X <- mnesia:table(shop)]));

ํ…Œ์ด๋ธ”์—์„œ ์กฐ๊ฑด์ ์œผ๋กœ ๋ฐ์ดํ„ฐ ์„ ํƒํ•˜๊ธฐ

    %% SQL equivalent
    %%  SELECT shop.item FROM shop
    %%  WHERE shop.quantity < 250;
    
    demo(reorder) ->
        do(qlc:q([X#shop.item || X <- mnesia:table(shop),
                                 X#shop.quantity < 250
                              ]));
                              
    demo(reorder2) ->
        do(qlc:q([{X#shop.item, X#shop.quantity} || X <- mnesia:table(shop),
                                 X#shop.quantity < 250
                              ]));

๋‘ ํ…Œ์ด๋ธ”๋กœ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ ์กฐ์ธํ•˜๊ธฐ

    %% SQL equivalent
    %%  SELECT shop.item, shop.quantity, cost.name, cost.price
    %%  FROM shop, cost
    %%  WHERE shop.item = cost.name
    %%    AND cost.price < 2
    %%    AND shop.quantity < 250
    demo(join2) ->
        do(qlc:q([ {X#shop.item, Y#cost.price} || X <- mnesia:table(shop),
                                 X#shop.quantity < 250,
                                 Y <- mnesia:table(cost),
                                 X#shop.item =:= Y#cost.name,
                                 Y#cost.price < 2
                              ]));
                              
    demo(join) ->
        do(qlc:q([X#shop.item || X <- mnesia:table(shop),
                                 X#shop.quantity < 250,
                                 Y <- mnesia:table(cost),
                                 X#shop.item =:= Y#cost.name,
                                 Y#cost.price < 2
                              ])).

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋ฐ์ดํ„ฐ ์ถ”๊ฐ€ํ•˜๊ณ  ์ œ๊ฑฐํ•˜๊ธฐ

ํ–‰(Row) ์ถ”๊ฐ€ํ•˜๊ธฐ

    add_shop_item(Name, Quantity, Cost) ->
        Row = #shop{item=Name, quantity=Quantity, cost=Cost},
        F = fun() ->
                    mnesia:write(Row)
            end,
        mnesia:transaction(F).

ํ–‰(Row) ์ œ๊ฑฐํ•˜๊ธฐ

    remove_shop_item(Item) ->
        Oid = {shop, Item},
        F = fun() ->
                    mnesia:delete(Oid)
            end,
        mnesia:transaction(F).

Mnesia ํŠธ๋žœ์žญ์…˜

  • ๋น„๊ด€์  ์ž ๊ธˆ ํ…Œ์ด๋ธ”์— ์ ‘๊ทผํ•  ๋•Œ ๋งˆ๋‹ค, ๋ ˆ์ฝ”๋“œ๋‚˜ ์ „์ฒด ํ…Œ์ด๋ธ”์— ๋Œ€ํ•ด์„œ Lock DeadLock ์ด ์ƒ๊ธธ ๊บผ ๊ฐ™๋‹ค๋ฉด, ํŠธ๋žœ์žญ์…˜ ์ค‘์ง€
  • ํŠธ๋ž™์žญ์…˜ ์ฝ”๋“œ๋Š” ์—ฌ๋Ÿฌ๋ฒˆ ์ˆ˜ํ–‰๋  ์ˆ˜ ์žˆ๋‹ค.
  • ํŠธ๋ž™์žญ์…˜ ์‹คํŒจ์‹œ ์ž ์‹œ ๋Œ€๊ธฐํ›„ ๋‹ค์‹œ ์‹œ๋„

  • ๋ถ€์ˆ˜์  ํšจ๊ณผ ๊ธˆ์ง€ - ์ด๋Ÿฐ ์ฝ”๋“œ๋Š” ์•ˆ๋˜์š”

      F = fun() ->
          ...
          io:format("reading ..."),
          ...
    

ํŠธ๋žœ์žญ์…˜ ์ค‘๋‹จ์‹œํ‚ค๊ธฐ

    farmer(Nwant) ->
        %% Nwant = Number of oranges the farmer wants to buy
        F = fun() ->
                    %% find the number of apples
                    [Apple] = mnesia:read({shop,apple}),
                    Napples = Apple#shop.quantity,
                    Apple1 = Apple#shop{quantity = Napples + 2*Nwant},
                    %% update the database
                    mnesia:write(Apple1),
                    %% find the number of oranges
                    [Orange] = mnesia:read({shop,orange}),
                    NOranges = Orange#shop.quantity,
                    if
                        NOranges >= Nwant ->
                            N1 = NOranges - Nwant,
                            Orange1 = Orange#shop{quantity=N1},
                            %% update the database
                            mnesia:write(Orange1);
                        true ->
                            %% Oops -- not enough oranges
                            mnesia:abort(oranges)
                    end
            end,
        mnesia:transaction(F).

์œ„์˜ ์ฝ”๋“œ๋ฅผ ์—ฐ์† ์‹คํ–‰

    test_mnesia:farmer(50).
    ํŠธ๋žœ์žญ์…˜: ์‚ฌ๊ณผ ๊ฐœ์ˆ˜๋ฅผ N*2 ๋งŒํผ ์—…๋ฐ์ดํŠธ
    ํŠธ๋žœ์žญ์…˜: ์˜ค๋ Œ์ง€ ๊ฐœ์ˆ˜๋ฅผ N ๋งŒํผ ์ œ๊ฑฐ 
    ํŠธ๋žœ์žญ์…˜ ์„ฑ๊ณต : ์ด์ œ ์˜ค๋ Œ์ง€์˜ ๊ฐœ์ˆ˜๋Š” 50
    test_mnesia:farmer(100).
    ํŠธ๋žœ์žญ์…˜: ์‚ฌ๊ณผ ๊ฐœ์ˆ˜๋ฅผ N*2 ๋งŒํผ ์—…๋ฐ์ดํŠธ
    ํŠธ๋žœ์žญ์…˜: ์˜ค๋ Œ์ง€ ๊ฐœ์ˆ˜๋ฅผ N ๋งŒํผ ์ œ๊ฑฐ 
    ํŠธ๋žœ์žญ์…˜ ์‹คํŒจ : 100๊ฐœ๊ฐ€ ์•ˆ๋‚จ์•„ ์žˆ๋‹ค.
    ํŠธ๋žœ์žญ์…˜ ์ทจ์†Œ

ํ…Œ์ด๋ธ”์— ๋ณต์žกํ•œ ๋ฐ์ดํ„ฐ ์ €์žฅํ•˜๊ธฐ

  • Mnesia ๋Š” ์–ผ๋žญ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋ฅผ ์ €์žฅํ•˜๋„๋ก ์„ค๊ณ„ : ๋ญ๋“ ์ง€ ํ…Œ์ด๋ธ”์— ์ €์žฅ ๊ฐ€๋Šฅ

  • Mnesia ๋Š” fragmented tables ์ง€์›( ์„œ๋ฒ„๋“ค์ด ํ…Œ์ด๋ธ”์˜ ๋‚ด์šฉ์„ ๋‚˜๋ˆ ๊ฐ€์ง€๊ณ  ์žˆ๋Š”๊ฑฐ)

      add_plans() ->
          D1 = #design{id = {joe,1},
                       plan = {circle,10}},
          D2 = #design{id = fred,
                       plan = {rectangle,10,5}},
          D3 = #design{id = {jane, {house,23}},
                       plan = {house,
                               [{floor, 1,
                                 [{doors, 3},
                                  {windows, 12},
                                  {rooms, 5}]},
                                {floor, 2,
                                 [{doors, 2},
                                  {rooms, 4},
                                  {windows, 15}]}]}},
          F = fun() ->
                      mnesia:write(D1),
                      mnesia:write(D2),
                      mnesia:write(D3)
              end,
          mnesia:transaction(F).
      
      get_plan(PlanId) ->
          F = fun() ->
                      mnesia:read({design, PlanId}) end,
          mnesia:transaction(F).
    

test_mnesia.erl

    -module(test_mnesia).
    -import(lists, [foreach/2]).
    -compile(export_all).
    
    %% IMPORTANT: The next line must be included
    %%            if we want to call qlc:q(...)
    
    -include_lib("stdlib/include/qlc.hrl").
    
    -record(shop, {item, quantity, cost}).
    -record(cost, {name, price}).
    -record(design, {id, plan}).
    
    do_this_once() ->
        mnesia:create_schema([node()]),
        mnesia:start(),
        mnesia:create_table(shop, [{disc_only_copies, [node()]}, {attributes, record_info(fields, shop)}]),
        mnesia:create_table(cost, [{disc_only_copies, [node()]}, {attributes, record_info(fields, cost)}]),
        mnesia:create_table(design, [{attributes, record_info(fields, design)}, {disc_only_copies, [node()]}]),
        mnesia:stop().
    
    start() ->
        mnesia:start(),
        mnesia:wait_for_tables([shop,cost,design], 20000).
    
    %% SQL equivalent
    %%  SELECT * FROM shop;
    
    demo(select_shop) ->
        do(qlc:q([X || X <- mnesia:table(shop)]));
    
    %% SQL equivalent
    %%  SELECT item, quantity FROM shop;
    
    demo(select_some) ->
        do(qlc:q([{X#shop.item, X#shop.quantity} || X <- mnesia:table(shop)]));
    
    %% SQL equivalent
    %%  SELECT shop.item FROM shop
    %%  WHERE shop.quantity < 250;
    
    demo(reorder) ->
        do(qlc:q([X#shop.item || X <- mnesia:table(shop),
                                 X#shop.quantity < 250
                              ]));
                              
    demo(reorder2) ->
        do(qlc:q([{X#shop.item, X#shop.quantity} || X <- mnesia:table(shop),
                                 X#shop.quantity < 250
                              ]));                          
    
    %% SQL equivalent
    %%  SELECT shop.item, shop.quantity, cost.name, cost.price
    %%  FROM shop, cost
    %%  WHERE shop.item = cost.name
    %%    AND cost.price < 2
    %%    AND shop.quantity < 250
    demo(join2) ->
        do(qlc:q([ {X#shop.item, Y#cost.price} || X <- mnesia:table(shop),
                                 X#shop.quantity < 250,
                                 Y <- mnesia:table(cost),
                                 X#shop.item =:= Y#cost.name,
                                 Y#cost.price < 2
                              ]));
                              
    demo(join) ->
        do(qlc:q([X#shop.item || X <- mnesia:table(shop),
                                 X#shop.quantity < 250,
                                 Y <- mnesia:table(cost),
                                 X#shop.item =:= Y#cost.name,
                                 Y#cost.price < 2
                              ])).
                           
                              
    do(Q) ->
        F = fun() ->
                    qlc:e(Q) end,
        {atomic, Val} = mnesia:transaction(F),
        Val.
    
    example_tables() ->
        [%% The shop table
         {shop, apple, 20, 2.3},
         {shop, orange, 100, 3.8},
         {shop, pear, 200, 3.6},
         {shop, banana, 420, 4.5},
         {shop, potato, 2456, 1.2},
         %% The cost table
         {cost, apple, 1.5},
         {cost, orange, 2.4},
         {cost, pear, 2.2},
         {cost, banana, 1.5},
         {cost, potato, 0.6}
         ].
    
    add_shop_item(Name, Quantity, Cost) ->
        Row = #shop{item=Name, quantity=Quantity, cost=Cost},
        F = fun() ->
                    mnesia:write(Row)
            end,
        mnesia:transaction(F).
    
    remove_shop_item(Item) ->
        Oid = {shop, Item},
        F = fun() ->
                    mnesia:delete(Oid)
            end,
        mnesia:transaction(F).
    
    farmer(Nwant) ->
        %% Nwant = Number of oranges the farmer wants to buy
        F = fun() ->
                    %% find the number of apples
                    [Apple] = mnesia:read({shop,apple}),
                    Napples = Apple#shop.quantity,
                    Apple1 = Apple#shop{quantity = Napples + 2*Nwant},
                    %% update the database
                    mnesia:write(Apple1),
                    %% find the number of oranges
                    [Orange] = mnesia:read({shop,orange}),
                    NOranges = Orange#shop.quantity,
                    if
                        NOranges >= Nwant ->
                            N1 = NOranges - Nwant,
                            Orange1 = Orange#shop{quantity=N1},
                            %% update the database
                            mnesia:write(Orange1);
                        true ->
                            %% Oops -- not enough oranges
                            mnesia:abort(oranges)
                    end
            end,
        mnesia:transaction(F).
    
    reset_tables() ->
        mnesia:clear_table(shop),
        mnesia:clear_table(cost),
        F = fun() ->
                    foreach(fun mnesia:write/1, example_tables())
            end,
        mnesia:transaction(F).
    
    add_plans() ->
        D1 = #design{id = {joe,1},
                     plan = {circle,10}},
        D2 = #design{id = fred,
                     plan = {rectangle,10,5}},
        D3 = #design{id = {jane, {house,23}},
                     plan = {house,
                             [{floor, 1,
                               [{doors, 3},
                                {windows, 12},
                                {rooms, 5}]},
                              {floor, 2,
                               [{doors, 2},
                                {rooms, 4},
                                {windows, 15}]}]}},
        F = fun() ->
                    mnesia:write(D1),
                    mnesia:write(D2),
                    mnesia:write(D3)
            end,
        mnesia:transaction(F).
    
    get_plan(PlanId) ->
        F = fun() ->
                    mnesia:read({design, PlanId}) end,
        mnesia:transaction(F).

์ฐธ๊ณ