【问题标题】:Laravel Eloquent Query OptimizationLaravel Eloquent 查询优化
【发布时间】:2018-05-27 21:11:56
【问题描述】:

我的应用程序的目的是按部门、日期(每天、每周、每月、每季度和每年)处理工资单数据,并将其显示在带有图表的仪表板中。

我有两 (2) 个表格,我上传 CSV 以获取数据:'attendance''payroll'

我有十 (10) 个学校,每个学校都由文本字段中的四 (4) 个数字标识。

**attendance** = date | school_code | department_name | child_count

**payroll** = date | school_code | teacher_name | department | hours | pay_rate

这就是我正在尝试的。我的查询非常昂贵。

public function index() {

    $schools     = array( '1001', '1003', '1004', '1005', '1007', '1008', '1009', '1010', '1011' );

    $infants   = 'Infants';
    $ones      = 'Ones';
    $twos      = 'Twos';
    $threes    = 'Threes';
    $fours     = 'Fours';
    $fives     = 'Fives';
    $schoolAge = 'School Age';
    $unknowns  = 'Unknown';
    $preK      = 'PreK';
    $office    = 'Office';

    $oneInfants    = ChildCount::where( 'school_code', $schools[0] )->where( 'department_name', $infants );
    $oneOnes       = ChildCount::where( 'school_code', $schools[0] )->where( 'department_name', $ones )->get();
    $oneTwos       = ChildCount::where( 'school_code', $schools[0] )->where( 'department_name', $twos )->get();
    $oneThrees     = ChildCount::where( 'school_code', $schools[0] )->where( 'department_name', $threes )->get();
    $oneFours      = ChildCount::where( 'school_code', $schools[0] )->where( 'department_name', $fours )->get();
    $oneFives      = ChildCount::where( 'school_code', $schools[0] )->where( 'department_name', $fives )->get();
    $oneSchoolAges = ChildCount::where( 'school_code', $schools[0] )->where( 'department_name', $schoolAge )->get();
    $oneUnknowns   = ChildCount::where( 'school_code', $schools[0] )->where( 'department_name', $unknowns )->get();
    $onePreK       = ChildCount::where( 'school_code', $schools[0] )->where( 'department_name', $preK )->get();
    $oneOffice     = ChildCount::where( 'school_code', $schools[0] )->where( 'department_name', $office )->get();


... **REPEATED FOR EACH SCHOOL** ...


    $oneMaster= DB::table( 'payrolls' )
                    ->join( 'child_counts', 'child_counts.school_code', '=', 'payrolls.school_code' )
                    ->where( 'payrolls.department', $infants )
                    ->where('payrolls.school_code',$schools[0])
                    ->take( 100 )
                    ->select( 'payrolls.*', 'child_days' )
                    ->get();

我没有适用于学校的模型,因为这是一个第三方应用程序,数据从我们的主要运营计划导出为 CSV。


如何在加入 child_counts && payrolls 之间的 school_code 时优化这些查询 - 一旦我能够遍历这些学校,部门和日期——我可以每天、每周、每月、每季度和每年查询;

提前致谢。

【问题讨论】:

    标签: php mysql laravel csv eloquent


    【解决方案1】:

    为您拥有的每个数据库表使用实际的 Eloquent 模型时,您将受益(如果您还没有工资单模型,请创建一个模型)。

    拥有Payroll 模型后,请确保在每个模型上定义了适当的relationship functions。 (在ChildCount 上建立关系并让您以后的生活更轻松,还要在Payroll 上定义反向关系。

    ChildCount.php

    public function payrolls() {
        return $this-hasMany(Payroll::class, 'school_code', 'school_code');
    }
    
    // I think you can even limit the payrolls in your relationship, not sure about this
    public function payrollsLimited() {
        return $this-hasMany(Payroll::class, 'school_code', 'school_code')->limit(100);
    }
    

    这样您就可以利用eager loading。这应该可以帮助您开始:

    $schoolCode = $schools[0];
    $departmentNames = [$infants, $ones, $twos, $threes]; // etc.
    $childCounts = ChildCount::where( 'school_code', $schoolCode)
      ->whereIn( 'department_name', $departmentNames )
      ->with(['payrolls']) // assumes the ChildCount model has a relationship with the payroll model
      ->get();
    

    上面的内容可以包装在一个 foreach 中,以循环遍历每所学校,但当然您也可以在一个查询中加载每所学校的所有数据。我不知道我们在谈论多少所学校,或者你的工资表有多大,但如果你想试试这个,你可以使用whereIn 而不是where

    祝你好运!

    PS:我想补充的最后一件事是,您可能想再看看您的数据库设计或模型名称。 payrollschildcounts 表通过 school_code 连接对我来说没有意义(ChildCount 是您模型的最佳名称吗?)

    【讨论】:

    • 谢谢佩皮恩。您的回答是彻底的、内容丰富的,并为我指明了一个更好的方向。
    • 您能否就如何加入 payrolls & child_counts 提出建议?我假设我应该制作一个 School 模型 - school_code 和一个 date 字段是我常用的字段。我应该加入哪个领域?我们有九 (9) 所学校和可追溯至两 (2) 年的工资/出勤数据 - 大约超过 50 万。 120,000 条记录:|再次感谢您!
    • 没问题,乐于助人!是的,理想情况下,您将创建一个School 模型(这将需要一个schools 数据库表,因此您必须首先将您的csv 导入这个new table,例如使用seeder)。在School 上添加关系后,您可以循环School::with(['payrolls', 'childcounts'])->get()。在这个重构的场景中,PayrollChildCount 可能不应该再有关系了,因为它们都与学校有关,而不是真正的彼此。
    • 你真的帮了大忙 - 再次感谢你 :-)
    猜你喜欢
    • 2021-07-22
    • 2017-10-07
    • 2020-09-24
    • 2018-02-27
    • 1970-01-01
    • 2020-12-17
    • 2019-06-28
    • 2017-11-14
    • 2018-07-25
    相关资源
    最近更新 更多