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;, .. . :
- depth_buy — ;
- depth_sell — ;
- transaction — = .
make_order_v2 :
- order_id — .
- order_type — . 21 — , 22 — .
- order_account — ( ).
- order_market — . .
- order_limit — . . , 100. .. 1.15btc 115.
- 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