繁体   English   中英

优化SQL查询的数量

[英]Optimize number for SQL queries

我使用此代码生成包含数据的图表:

    @GetMapping("/terminals")
    public ResponseEntity<Map<String, List<TopTerminalsDTO>>> getTopTerminals(
            @RequestParam(value = "start_date", required = true) String start_date,
            @RequestParam(value = "end_date", required = true) String end_date) {


        final List<PaymentTransactionsDailyFacts> list = dashboardService.findTop_Terminals(start_dateTime, end_dateTime);

        final Collector<PaymentTransactionsDailyFacts, List<TopTerminalsDTO>, List<TopTerminalsDTO>> terminalsCollector = Collector
                .of(ArrayList::new, (terminals, p) -> terminals.add(mapper.toTopTerminalsDTO(p)),
                        (accumulator, terminals) -> {
                            accumulator.addAll(terminals);
                            return accumulator;
                        });

        final Map<String, List<TopTerminalsDTO>> final_map = list.stream().filter(p -> p.getTerminal_id() != null)
                .collect(Collectors.groupingBy(p -> getTerminalName(p.getTerminal_id()), terminalsCollector));

        return ResponseEntity.ok(final_map);
    }

    private String getTerminalName(Integer id) {      
        Optional<Terminals> obj = terminalService.findById(id);       
        return obj.map(Terminals::getName).orElse("");
    }

但我注意到getTerminalName被调用超过10次以从数字转换名称。 你知道我如何通过一些优化减少通话次数吗?

修改findTop_TerminalsPaymentTransactionsDailyFacts以包含名称(使用SQL LEFT JOIN子句)。


或者,扫描列表中的所有终端ID,然后调用List<Terminals> list = terminalService.findByIds(idList); 使用SQL IN子句获取所有终端的方法。

注意:注意限制多少? 标记可以在SQL语句中。

然后构建Map<Integer, String>映射终端id到name,并用映射查找替换getTerminalName方法。

听起来像是临时缓存的情况,仅限于此请求,或者如果终端名称足够稳定,则可能更长。

显然,像幕后的ehCache这样的东西很适合这种情况,但我经常会受到一些缓存的策略诱惑,特别是如果我不想让缓存的值超出这个直接请求的话。

例如:

    TerminalNameCache cache = new TerminalNameCache();

    final Map<String, List<TopTerminalsDTO>> final_map = list.stream()
            .filter(p -> p.getTerminal_id() != null)
            .collect(Collectors.groupingBy(
                    p -> cache.getTerminalName(p.getTerminal_id()),
                    terminalsCollector));

然后, TerminalNameCache只是父Controller类中的内部类。 这是为了允许它从问题中调用现有的private String getTerminalName(Integer id)方法(如下面的ParentControllerClass所示):

private class TerminalNameCache {
    private final Map<Integer, String> cache = new ConcurrentHashMap<>();

    private String getTerminalName(Integer id) {
        return cache.computeIfAbsent(id,
                id2 -> ParentControllerClass.this.getTerminalName(id2));
    }
}

如果这看起来像是一种模式,那么将缓存重构为更可重用的东西是值得的。 例如,这可以基于缓存对泛型函数的调用:

public class CachedFunction<T, R> implements Function<T, R> {
    private final Function<T, R> function;
    private final Map<T, R> cache = new ConcurrentHashMap<>();

    public CachedFunction(Function<T, R> function) {
        this.function = function;
    }

    @Override
    public R apply(T t) {
        return cache.computeIfAbsent(t, t2 -> function.apply(t2));
    }
}

然后将这样使用:

    CachedFunction<Integer, String> cachedFunction = new CachedFunction<>(
            id -> getTerminalName(id));

    final Map<String, List<TopTerminalsDTO>> final_map = list.stream()
            .filter(p -> p.getTerminal_id() != null)
            .collect(Collectors.groupingBy(
                    p -> cachedFunction.apply(p.getTerminal_id()),
                    terminalsCollector));

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM