Java 与在应用程序中执行计算相比,在sql中执行计算的优缺点是什么

Java 与在应用程序中执行计算相比,在sql中执行计算的优缺点是什么,java,.net,sql,performance,postgresql,Java,.net,Sql,Performance,Postgresql,shopper表中有以下字段: id (bigint),amount (numeric(19,2)),createddate (timestamp) 比方说,我有上表。我想要昨天和明天的唱片 通过将金额打印为美分生成报告 一种方法是在我的java应用程序中执行计算并执行一个简单的查询 Date previousDate ;// $1 calculate in application Date todayDate;// $2 calculate in application select a

shopper
表中有以下字段:

id (bigint),amount (numeric(19,2)),createddate (timestamp)
比方说,我有上表。我想要昨天和明天的唱片 通过将金额打印为美分生成报告

一种方法是在我的java应用程序中执行计算并执行一个简单的查询

Date previousDate ;// $1 calculate in application

Date todayDate;// $2 calculate in application

select amount where createddate between $1 and $2 
然后在java应用程序中循环记录并将金额转换为美分,然后生成报告

另一种方法类似于在sql查询本身中执行计算:

select cast(amount * 100 as int) as "Cents"
from shopkeeper  where createddate  between date_trunc('day', now()) - interval '1 day'  and  date_trunc('day', now())
然后循环浏览记录并生成报告

在一种方式中,我的所有处理都在java应用程序中完成,并触发一个简单的查询。 在另一种情况下,所有转换和计算都在Sql查询中完成

上面的用例只是一个示例,在实际场景中,一个表可以有许多列,这些列需要类似的处理


您能告诉我哪种方法在性能和其他方面更好吗?为什么?

这取决于很多因素,但最关键的是:

  • 计算的复杂性(更喜欢在应用程序服务器上进行复杂的运算,因为这会向外扩展;而不是在db服务器上进行扩展)
  • 数据量(如果您需要访问/聚合大量数据,在db服务器上执行此操作将节省带宽,如果聚合可以在索引内完成,则可以节省磁盘io)
  • 便利性(对于复杂的工作,sql不是最好的语言——特别是对于过程性工作,sql不是最好的语言,但是对于基于集合的工作,sql非常好;但是错误处理很糟糕)
与往常一样,如果您将数据带回应用程序服务器,则最小化列和行将对您有利。确保对查询进行了调优并对其进行了适当的索引将有助于这两种情况

请注意:

然后循环浏览记录

在sql中,循环记录几乎总是错误的-最好编写基于集合的操作

作为一般规则,我更喜欢将数据库的任务保持在最低限度“存储此数据,获取此数据”-然而,在服务器上进行优雅的查询可以节省大量带宽的情况下,总会有一些例子

还要考虑:如果这在计算上很昂贵,它能被缓存到某个地方吗


如果你想要一个准确的“哪个更好”;用两种方式编写代码并进行比较(注意两种方法的初稿都可能没有100%调优)。但将典型用法考虑在内:如果在现实中,它一次被调用5次(分别),那么模拟一下:不要只比较一个“1对1”。

一般来说,如果同一个或其他项目中的其他模块或组件也有可能需要获得这些结果,那么就在SQL中执行操作。在服务器端完成的原子操作也更好,因为您只需要从任何db管理工具调用存储的过程即可获得最终值,而无需进一步处理

在某些情况下,这并不适用,但当它适用时,它是有意义的。一般来说,db box具有最好的硬件和性能。

在这种情况下,使用SQL进行计算可能会稍微好一些,因为数据库引擎可能比Java具有更高效的十进制算术例程

一般来说,虽然行级计算没有太大差异

它真正起作用的是:

  • 聚合计算,如SUM()、AVG()、MIN()、MAX(),在这里,数据库引擎将比Java实现快一个数量级
  • 计算用于筛选行的任何位置。在数据库中进行过滤比读取一行然后丢弃它要有效得多

如果我们能够确定业务实现中的目标,那么在前端还是后端执行计算在很大程度上取决于我们。在那个时候,java代码可能比sql代码表现得更好,两者都写得很好,反之亦然。但是,如果您感到困惑,您可以尝试先确定-

  • 如果您可以通过数据库sql实现一些简单的功能,那么最好使用它,因为db的性能会更好,可以在那个里进行计算,然后使用结果获取。但是,如果实际的计算需要从这里到那里进行太多的计算,那么您可以使用应用程序代码。为什么?因为在大多数情况下,类似于循环的场景并不是由sql来处理的,而前端语言更适合于这些情况
  • 如果需要从多个地方进行类似的计算,那么显然将计算代码放在db端将更好地保持在同一个地方
  • 如果需要通过许多不同的查询进行大量计算以获得最终结果,那么也可以使用db end,因为您可以将相同的代码放在存储过程中,这样比从后端检索结果然后在前端计算结果的性能更好

  • 在决定将代码放置在何处之前,您还可以考虑许多其他方面。有一种看法是完全错误的——一切都可以用Java(应用程序代码)和/或db(sql代码)做得最好。

    让我用一个比喻:如果你想在巴黎买一条金项链,金匠可以坐在开普敦或巴黎,这是技能和品味的问题。但你永远不会为了这个目的把成吨的金矿从南非运到法国。矿石在采矿现场(或至少在一般区域)进行加工,只有黄金可以运输。应用程序和数据库也是如此

    就PostgreSQL而言,您几乎可以在服务器上高效地执行任何操作。RDBMS擅长于复杂的查询。对于过程性需求,您可以从各种类型中进行选择:tcl、python、perl和更多。不过,我用的大多是

    最坏的情况是重复出现
    import psycopg2
    import psycopg2.extras
    from talib import func
    import timeit
    import numpy as np
    with psycopg2.connect('dbname=xyz user=xyz') as conn:
    with conn.cursor() as cur:
    t0 = timeit.default_timer()
    cur.execute('select distinct symbol from ohlc_900 order by symbol')
    for symbol in cur.fetchall():
    cur.execute('select c from ohlc_900 where symbol = %s order by ts', symbol)
    ohlc = np.array(cur.fetchall(), dtype = ([('c', 'f8')]))
    wma = func.WMA(ohlc['c'], 10)
    # print(*symbol, wma[-1])
    print(timeit.default_timer() - t0)
    conn.close()
    
    """
    if the period is 10
    then we need 9 previous candles or 15 x 9 = 135 mins on the interval department
    we also need to start counting at row number - (count in that group - 10)
    For example if AAPL had 134 coins and current row number was 125
    weight at that row will be weight = 125 - (134 - 10) = 1
    10 period WMA calculations
    Row no Weight c
    125 1
    126 2
    127 3
    128 4
    129 5
    130 6
    131 7
    132 8
    133 9
    134 10
    """
    query2 = """
    WITH
    condition(sym, maxts, cnt) as (
    select symbol, max(ts), count(symbol) from ohlc_900 group by symbol
    ),
    cte as (
    select symbol, ts,
    case when cnt >= 10 and ts >= maxts - interval '135 mins'
    then (row_number() over (partition by symbol order by ts) - (cnt - 10)) * c
    else null
    end as weighted_close
    from ohlc_900
    INNER JOIN condition
    ON symbol = sym
    WINDOW
    w as (partition by symbol order by ts rows between 9 preceding and current row)
    )
    select symbol, sum(weighted_close)/55 as wma
    from cte
    WHERE weighted_close is NOT NULL
    GROUP by symbol ORDER BY symbol
    """
    with psycopg2.connect('dbname=xyz user=xyz') as conn:
    with conn.cursor() as cur:
    t0 = timeit.default_timer()
    cur.execute(query2)
    # for i in cur.fetchall():
    # print(*i)
    print(timeit.default_timer() - t0)
    conn.close()