简体   繁体   English

如何优化 laravel eloquent 查询?

[英]How to optimize laravel eloquent query?

So I have orders model and table .所以我有订单modeltable

it contains integer fields that I want to calculate to find daily, monthly and yearly earnings.它包含 integer 字段,我想计算这些字段以查找每日、每月和每年的收入。 My current solution works fine but as shown in the image below it runs 3 queries to find all of them.我当前的解决方案工作正常,但如下图所示,它运行 3 个查询来找到所有这些。 is there any way better to calculate the earning without running the query 3 times?有没有更好的方法来计算收入而不运行查询 3 次?

I have also tried getting all the orders into one variable then using laravel's collection methods to calculate earnings, that also works but it's slower than my current solution.我还尝试将所有订单放入一个变量中,然后使用 laravel 的收集方法来计算收入,这也有效,但它比我目前的解决方案慢。

    public function index()
{

    $dailyEarning = Order::whereDate('created_at', Carbon::today())->get()->sum(function ($order) {
        return (($order->cost - $order->product->original_cost) * $order->quantity);
    });

    $monthlyEarning = Order::whereBetween('created_at', [
        Carbon::today()->startOfMonth(),
        Carbon::today()->endOfMonth(),
    ])->get()->sum(function ($order) {
        return (($order->cost - $order->product->original_cost) * $order->quantity);
    });

    $yearlyEarning = Order::whereBetween('created_at', [
        Carbon::today()->startOfYear(),
        Carbon::today()->endOfYear(),
    ])->get()->sum(function ($order) {
        return (($order->cost - $order->product->original_cost) * $order->quantity);
    });

    return view('admin.home',[
        'dailyEarning' => $dailyEarning,
        'monthlyEarning' => $monthlyEarning,
        'yearlyEarning' => $yearlyEarning,
    ]);
}

Orders table schema:订单表架构:

   public function up()
{
    Schema::create('orders', function (Blueprint $table) {
        $table->id();

        $table->unsignedBigInteger('product_id');
        $table->foreign('product_id')->references('id')->on('products')->onDelete('restrict');

        $table->unsignedBigInteger('invoice_id');
        $table->foreign('invoice_id')->references('id')->on('invoices')->onDelete('cascade');

        $table->double('cost');
        $table->double('quantity');

        $table->timestamps();
    });
}

Products table schema:产品表架构:

  public function up()
{
    Schema::create('products', function (Blueprint $table) {
        $table->id();

        $table->string('name');
        $table->string('code');
        $table->string('brand');

        $table->double('quantity')->default(0);
        $table->double('original_cost')->default(0);
        $table->double('cost')->default(0);

        $table->string('photo')->default('no-image');
        $table->timestamps();
    });
}

Create an OrderSummary table.创建一个 OrderSummary 表。 The idea should be that you run the monthly (to date) and yearly (to date) queries only once per day (automatically).这个想法应该是您每天(自动)只运行一次每月(迄今为止)和每年(迄今为止)查询。

YTD Sales = Yesterday's YTD Sales + Today's Sales MTD Sales = Yesterday's MTD Sales + Today's Sales YTD 销售额 = 昨天的 YTD 销售额 + 今天的销售额 MTD 销售额 = 昨天的 MTD 销售额 + 今天的销售额

(Both presume that yesterday is the same year, an the same month. If not, account or it) (两者都假设昨天是同一年,同一个月。如果不是,帐户或它)

Each time, you'll still run the query to get the current day's sales.每次,您仍将运行查询以获取当天的销售额。 But you will query an OrderSummary single row for the previous day with columns:但是您将查询前一天的 OrderSummary 单行,其中包含以下列:

id |编号 | date |日期 | YTD Sales |年初至今销售额 | Monthly Sales月销售额

If you're using caching, you'll cache those results as well.如果您使用缓存,您也将缓存这些结果。

If it returns zero records for the previous day, then you'll need to execute your queries and update OrderSummary.如果它返回前一天的零记录,那么您需要执行查询并更新 OrderSummary。 However, you can execute these in the background with a CRON so they are ready beforehand.但是,您可以使用 CRON 在后台执行这些操作,以便事先准备好。

Note: Since you may need to account for order reversals, so the full YTD and MTD queries would have to be run daily (versus just adding the previous day's completed order total to the prior amounts to update them).注意:由于您可能需要考虑订单冲销,因此必须每天运行完整的 YTD 和 MTD 查询(而不是仅将前一天的已完成订单总额添加到先前的金额中以更新它们)。

Without seeing the structure of the tables I don't think it's possible to provide a specific working solution for this problem.在没有看到表格结构的情况下,我认为不可能为这个问题提供特定的工作解决方案。 However, in principle the way to resolve this is almost certainly to move as much of this work as possible to the database and use subqueries to calculate the different values.然而,原则上解决这个问题的方法几乎可以肯定是将尽可能多的工作转移到数据库中,并使用子查询来计算不同的值。

Most SQL implementations have a SUM() implementation so it should be possible to use that to move aggregating the values into the database for each individual query.大多数 SQL 实现都有一个SUM()实现,因此应该可以使用它将聚合值移动到每个单独查询的数据库中。 Then make each value a subquery of a larger query, and that should achieve what you want.然后使每个值成为更大查询的子查询,这应该可以实现您想要的。

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

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