Pematung

Kemarin saya duduk dengan tenang, seperti biasa saya tidak mengganggu siapa pun. Disini, dari dua kontak yang berbeda, mereka hampir secara bersamaan mengirimkan link ke tweet terkenal tentang JSON dari SQL. Salah satu pesan terlihat seperti ini:





Itu sudah menjadi tantangan langsung. Saya tidak bisa mengabaikannya. Jadi saya memutuskan untuk menceritakan sebuah cerita yang masih menimbulkan perasaan ambivalen dalam diri saya. Tiga tahun kemudian.



Pada waktu yang diberkati itu, semua orang memimpikan crypto, terlibat dalam ICO dan pertukaran crypto yang terpahat. Benar-benar sesuatu yang baru. Saya memiliki pengalaman dalam menciptakan sistem untuk manajemen aset klasik (saham, obligasi, dll.). Masalahnya adalah itu terbentuk di sekitar sistem akuntansi. Saya ingin menyadari diri saya dalam menciptakan pertukaran. Pantas saja saya menyelam ke dalam kuali mendidih ini dengan senang hati.



Ini latar belakangnya. Ada banyak hal menarik, tetapi hari ini saya ingin memberi tahu Anda tentang kasus tertentu - cara kami membuat pencocokan kami.



Matcher, inilah inti dari pertukarannya. Di sinilah transaksi terjadi. Dalam stereotip klasik, ini adalah subsistem berkinerja tinggi. Tapi ini benar untuk pertukaran besar. Di sana, aplikasi terbuka untuk jual beli mencapai ratusan ribu.



“ ” . . — , . — .



.



Java . , , . , . “” . .



. , , “” . . , 270 . RabbitMQ. ….



. . 2 . , , . , , .



. . .. , … , .. . - :



! ()

, . . … . .



, . , . , . — .



, . , 100, 5. 100 7 . , .



SQL . , . MySQL . , MySQL . .. . :



SET depth_sell.`limit` = depth_sell.`limit` - IF(
                    ((@tofill := IF(
                            depth_sell.`limit` <= @limit,
                            depth_sell.`limit`,
                            @limit
                        ))
                        + (@limit := @limit - @tofill)),
                    @tofill,
                    @tofill
                ),
        depth_sell.`executed` = @tofill
WHERE @limit > 0;




@limit := @limit - @tofill


() .



IN MEMORY . .. . .



. — . . , , .



CREATE TABLE transactions
(
    id INT AUTO_INCREMENT PRIMARY KEY,
    moment TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
    side1 INT NOT NULL,
    side2 INT NOT NULL,
    price BIGINT NOT NULL,
    volume BIGINT NOT NULL
);

CREATE TABLE depth_buy
(
    id BIGINT PRIMARY KEY NOT NULL AUTO_INCREMENT,
    order_id  BIGINT NOT NULL,
    type INT DEFAULT '0' NOT NULL,
    market INT DEFAULT '0' NOT NULL,
    account INT NOT NULL,
    price BIGINT DEFAULT '0' NOT NULL,
    `limit` BIGINT DEFAULT '0' NOT NULL,
    taker INT,
    rev_price BIGINT NOT NULL,
    executed BIGINT
) ENGINE = MEMORY;

CREATE TABLE depth_sell
(
    id BIGINT PRIMARY KEY NOT NULL AUTO_INCREMENT,
    order_id  INT NOT NULL,
    type INT DEFAULT '0' NOT NULL,
    market INT DEFAULT '0' NOT NULL,
    account INT NOT NULL,
    price BIGINT DEFAULT '0' NOT NULL,
    `limit` BIGINT DEFAULT '0' NOT NULL,
    taker INT,
    rev_price BIGINT NOT NULL,
    executed  BIGINT
) ENGINE = MEMORY;


CREATE PROCEDURE `make_order_v2`(IN order_id INT,
                                 IN order_type INT,
                                 IN order_account INT,
                                 IN order_market INT,
                                 IN order_limit BIGINT,
                                 IN order_price BIGINT)
BEGIN
    START TRANSACTION;
    SET @limit := order_limit;
    IF order_type = 21 THEN
        UPDATE depth_sell
            INNER JOIN (
                SELECT id
                FROM depth_sell
                WHERE market = order_market
                  AND depth_sell.price <= order_price
                ORDER BY depth_sell.price + id ASC
            ) source ON depth_sell.id = source.id
        SET depth_sell.taker      = order_id,
            depth_sell.`limit`    = depth_sell.`limit` - IF(
                    ((@tofill := IF(
                            depth_sell.`limit` <= @limit,
                            depth_sell.`limit`,
                            @limit
                        ))
                        + (@limit := @limit - @tofill)),
                    @tofill,
                    @tofill
                ),
            depth_sell.`executed` = @tofill
        WHERE @limit > 0;

        INSERT INTO transactions (moment, side1, side2, price, volume)
        SELECT now(), depth_sell.id, order_id, depth_sell.price, depth_sell.executed
        FROM depth_sell
        WHERE depth_sell.`taker` = order_id;

        DELETE
        FROM depth_sell
        WHERE market = order_market
          AND depth_sell.`limit` = 0;

        IF @limit > 0 THEN
            INSERT INTO depth_buy (order_id, type, market, account, price, rev_price, `limit`)
            VALUES (order_id, order_type, order_market, order_account, order_price, -order_price, @limit);
        END IF;
    ELSE
        UPDATE depth_buy
            INNER JOIN (
                SELECT id
                FROM depth_buy
                WHERE market = order_market
                  AND depth_buy.price >= order_price
                ORDER BY depth_buy.rev_price - id ASC
            ) source ON depth_buy.id = source.id
        SET depth_buy.taker      = order_id,
            depth_buy.`limit`    = depth_buy.`limit` - IF(
                    ((@tofill := IF(
                            depth_buy.`limit` <= @limit,
                            depth_buy.`limit`,
                            @limit
                        ))
                        + (@limit := @limit - @tofill)),
                    @tofill,
                    @tofill
                ),
            depth_buy.`executed` = @tofill
        WHERE @limit > 0;

        INSERT INTO transactions (moment, side1, side2, price, volume)
        SELECT now(), depth_buy.id, order_id, depth_buy.price, depth_buy.executed
        FROM depth_buy
        WHERE depth_buy.`taker` = order_id;

        DELETE
        FROM depth_buy
        WHERE market = order_market
          AND depth_buy.`limit` = 0;
        IF @limit > 0 THEN
            INSERT INTO depth_sell (order_id, type, market, account, price, rev_price, `limit`)
            VALUES (order_id, order_type, order_market, order_account, order_price, -order_price, @limit);
        END IF;
    END IF;
    COMMIT;
END;


CREATE PROCEDURE do_load_matcher_v2(IN market INT)
BEGIN
    DECLARE count INT DEFAULT 100000;
    WHILE count > 0 DO
            call make_order_v2(
                    count,
                    IF(count % 2 = 0, 21, 22),
                    1,
                    market,
                    FLOOR(1 + (RAND() * 1000)),
                    FLOOR(1 + (RAND() * 1000))
                );
            SET count = count - 1;
        END WHILE;
END;


, .. . :



  1. depth_buy — ;
  2. depth_sell — ;
  3. transaction — = .


make_order_v2 :



  1. order_id — .
  2. order_type — . 21 — , 22 — .
  3. order_account — ( ).
  4. order_market — . .
  5. order_limit — . . , 100. .. 1.15btc 115.
  6. order_price — . .


, . — . , . .



, .



, . . 100 . 95 . 1.46 . 570 . .



, . . , . . .. .



, ? :



  • . .
  • , , . .


:



  • . , . .
  • . . .


Tentu saja, saya tidak berbagi optimisme penulis posting asli bahwa semuanya dapat dilakukan melalui DBMS, tetapi pengalaman menunjukkan bahwa semuanya dapat dilakukan melalui DBMS. Jika Anda menghendaki. Karena itu, Anda perlu berhati-hati dengan keinginan Anda. Jika tidak, Anda harus mengalami sakit mental selama bertahun-tahun.



Semuanya bagus!



Tweet asli




All Articles