oracle order by后查询效率低怎么优化_现代化的Java(十)——订单查询

接下来要做撮合服务,我们要先让 counter 提供订单查询服务。

不让撮合系统直接从数据库里获取,是出于设计上的考虑。这样撮合服务不需要知道数据如何存储,从本地的模拟测试 Actor ,到单节点连接数据库的简单结构,再到分布式数据和集群节点,无论下单系统如何演进,撮合对接时不需要修改。

这里需要写一些比较复杂的查询,例如给定一个order id,找出它的下一条,也就是比它更大的id中最小的一个。虽然理想状态下这个序列应该是连续的,但是实践中我们不能期待分布式系统永远可靠,每一个节点都应该考虑其它节点不可靠时的应对。同样指定id返回对应记录的查询,也要考虑没有匹配记录时的处理。

这种情况,无论 clojure.java.jdbc 还是 java 的 hibernate 体系,能提供的帮助都比较有限。我们还是要手工写一点儿查询。

我们应该接受一个事实,就是每一个软件开发人员,应该尽量保持自己的知识范围比工作中常用的要“大一圈”。尽管现在数据库访问越来越方便,作应用开发的程序员,特别是后端开发人员,还是应该了解一些 SQL 编写的知识,特别是不能局限于 MySQL 体系。同样道理,仅仅 MSSQL 或 Oracle 也是不行的,哪怕仅仅从实用角度考虑,掌握一种服务器型的关系数据库的 SQL ,和一种内存嵌入式关系型数据库(例如 SQLite )的 SQL ,也能够有效提升工作效率。

再例如,我并不是 JVM 专家,我的工作中也不会直接面对 JVM 的精细量化调节,但是十六年前我第一次接触 Java 项目,就是从逆向乙方的 java 版 sdk ,重新实现 c sharp 版本开始。我们不应该指望学习一次技术,就可以吃一辈子,也不应该寄希望于阻止团队前进来为自己保值。市场在竞争,在优胜劣汰,我亲眼见过安心睡觉五六年后,惊愕的发现自己因为错过了技术升级的机会,只能被淘汰的企业。企业可以破产,个人如何选择未来?机会最终还是会归于有准备的人。希望大家能够理解一件事,团队和个人的学习,都是非常重要的事情,我们都知道坚持锻炼是保持健康的根本措施,那么坚持学习也一样。

这里我们要在 order.clj 中加入查找“比给定 id 大的最小 id”所对应的记录,这个查询是:

with last as (select min(id) from order_flow) 
select order_flow.id, account_id, price, content 
from order_flow join last where order_flow.id=last.id;

对应的 Clojure 代码,用 jaskell.sql 工具写出来是:

(def find-last-query
  (-> (with [:last as
             (select (f :min :id) :as :id
                     from :order_flow
                     where :id :> (p 0))]
            select [:order_flow.id :content :price]
            from :order_flow
            join :last on :order_flow.id := :last.id)
      (.cache)))

现在我们可以写出 place-order 的逆操作 load-order :

(defmulti load-order (fn [data] (get-in data [:content "category"])))

(defmethod load-order "limit-ask" [data]
  (doto (LimitAsk.)
    (.setId (:id data))
    (.setPrice (:price data))
    (.setSymbol (get-in data [:content "symbol"]))
    (.setQuantity (get-in data [:content "quantity"]))
    (.setCompleted (get-in data [:content "completed"]))
    (.setAccountId (get-in data [:content "account-id"]))))

(defmethod load-order "limit-bid" [data]
  (doto (LimitBid.)
    (.setId (:id data))
    (.setPrice (:price data))
    (.setSymbol (get-in data [:content "symbol"]))
    (.setQuantity (get-in data [:content "quantity"]))
    (.setCompleted (get-in data [:content "completed"]))
    (.setAccountId (get-in data [:content "account-id"]))))

(defmethod load-order "market-ask" [data]
  (doto (MarketAsk.)
    (.setId (:id data))
    (.setSymbol (get-in data [:content "symbol"]))
    (.setQuantity (get-in data [:content "quantity"]))
    (.setCompleted (get-in data [:content "completed"]))
    (.setAccountId (get-in data [:content "account-id"]))))

(defmethod load-order "market-bid" [data]
  (doto (MarketBid.)
    (.setId (:id data))
    (.setSymbol (get-in data [:content "symbol"]))
    (.setQuantity (get-in data [:content "quantity"]))
    (.setCompleted (get-in data [:content "completed"]))
    (.setAccountId (get-in data [:content "account-id"]))))

(defmethod load-order "cancel" [data]
  (doto (Cancel.)
    (.setId (:id data))
    (.setSymbol (get-in data [:content "symbol"]))
    (.setAccountId (get-in data [:content "account-id"]))
    (.setOrderId (get-in data [:content "order-id"]))))

在保存数据的时候,我们是先 place-order 生成一致的 json 后执行 save 入库。读取数据则相反,根据 find-by 和 find-next 操作查询到的数据,通过 load-order 或 NoteMore/NotFound 的构造返回查询结果,那么 find-by 和 find-next 代码是:

(defn find-by
  [order-id]
  (if-some [data (j/get-by-id @db :order_flow order-id)]
    (load-order data)
    (doto (OrderNotFound.)
      (.setId order-id))))

(defn find-next
  [from-id]
  (let [data (j/query @db [(.script find-last-query) from-id])]
    (if (not-empty data)
      (load-order (first data))
      (doto (OrderNoMore.)
        (.setPositionId from-id)))))

有了这两个函数,我们就可以……且慢还是写写个测试吧,首先我们准备一些测试数据:

(ns liu.mars.market.test-data)

(def sym "btcusdt")

(def note-paper
  {
    :limit-ask  [{
    :id 1 :symbol sym :price 34522M :quantity 1 :account-id 3223421}
                {
    :id 2 :symbol sym :price 34512M :quantity 10001 :account-id 3223421}
                {
    :id 3 :symbol sym :price 34525M :quantity 10020 :account-id 34223421}
                {
    :id 4 :symbol sym :price 34562M :quantity 1000 :account-id 3422341}
                {
    :id 5 :symbol sym :price 44522M :quantity 10000 :account-id 34223421}]
   :limit-bid  [{
    :id 6 :symbol sym :price 24522M :quantity 1 :account-id 34223421}
                {
    :id 7 :symbol sym :price 3412M :quantity 10001 :account-id 34223421}
                {
    :id 8 :symbol sym :price 32525M :quantity 10020 :account-id 34223421}
                {
    :id 9 :symbol sym :price 31562M :quantity 1000 :account-id 34223421}
                {
    :id 10 :symbol sym :price 1522M :quantity 9999 :account-id 34223421}]
   :market-ask [{
    :id 11 :symbol sym :quantity 1 :account-id 34223421}
                {
    :id 12 :symbol sym :quantity 10001 :account-id 3422342}
                {
    :id 13 :symbol sym :quantity 10020 :account-id 34223421}
                {
    :id 14 :symbol sym :quantity 1000 :account-id 3423421}
                {
    :id 15 :symbol sym :quantity 10000 :account-id 34223421}]
   :market-bid [{
    :id 16 :symbol sym :quantity 12433 :account-id 34223421}
                {
    :id 17 :symbol sym :quantity 10001 :account-id 34223421}
                {
    :id 18 :symbol sym :quantity 10020 :account-id 34223421}
                {
    :id 19 :symbol sym :quantity 1000 :account-id 34223421}
                {
    :id 20 :symbol sym :quantity 9999 :account-id 3422421}]
   :cancel     [{
    :id 21 :symbol sym :account-id 4223421 :order-id 23341}
                {
    :id 22 :symbol sym :account-id 3423421 :order-id 23342}
                {
    :id 23 :symbol sym :account-id 3422321 :order-id 2341}
                {
    :id 24 :symbol sym :account-id 3423421 :order-id 23}
                {
    :id 25 :symbol sym :account-id 3423421 :order-id 9}]})

后面的测试会反复使用这组数据,接下来是测试代码:

(ns liu.mars.market.inner-find-test
  (:require [clojure.java.jdbc :as j])
  (:require [liu.mars.market.order :refer :all])
  (:require [clojure.test :refer :all])
  (:require [liu.mars.market.test-data :as data]
            [liu.mars.market.config :as cfg])
  (:import (liu.mars.market.messages LimitAsk LimitBid MarketAsk MarketBid)))

(testing "inner testing for order module"
  (j/delete! @cfg/db :order_flow ["id < ?" 26])
  (testing "tests for limit ask orders save and reload"
    (doseq [item (:limit-ask data/note-paper)]
      (let [data (assoc item :completed 0 :category "limit-ask")]
        (save data)
        (let [order (find-by (:id data))]
          (is (instance? LimitAsk order))
          (is (= (:id data) (.getId order)))
          (is (= 0 (:completed data) (.getCompleted order)))
          (is (= (:quantity data) (.getQuantity order)))
          (is (= (:account-id data) (.getAccountId order)))
          (is (= (:symbol data)) (.getSymbol order))
          (is (= (:price data) (.getPrice order)))))))
  (testing "tests for limit bid orders save and reload"
    (doseq [item (:limit-bid data/note-paper)]
      (let [data (assoc item :completed 0 :category "limit-bid")]
        (save data)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值