大数据集的Laravel API加载速度非常慢

问题描述 投票:0回答:1

我已经制定了一个 Laravel 应用的api路由从mysql db加载数据,controller动作执行一个嵌套的DB查询,并返回一个集合;默认情况下Laravel将返回的集合转换为JSON,下面是我的contrller动作。

public function index()
    {
        $admin0 = 2;

        return DB::table('commodities_monthly_prices as CMP')
            ->join('locations', 'CMP.location_id', '=', 'locations.id')
            ->where('locations.admin0', $admin0)
            ->join('global_admins', 'locations.admin0', '=', 'global_admins.admin0_code')
            ->join('commodities', 'CMP.commodity_id', '=', 'commodities.id')
            ->join('price_types', 'CMP.price_type_id', '=', 'price_types.id')
            ->join('measure_units', 'CMP.measure_unit_id', '=', 'measure_units.id')
            ->select('commodities.name AS commodity_name', 'price_types.name AS type_name',
                'measure_units.name AS unit_name', 'global_admins.admin0_code AS admin0',
                'global_admins.admin0_name AS country_name', 'global_admins.admin1_code AS admin1',
                'global_admins.admin1_name AS governorate_name')
            ->selectRaw('date(concat_WS(\'-\', CMP.price_year, CMP.price_month, \'01\')) as date, ROUND(AVG(CMP.price) / 1000, 3) as price')
            ->groupBy('date', 'commodity_name', 'type_name', 'unit_name', 'global_admins.admin0_name',
                'global_admins.admin0_code', 'global_admins.admin1_name', 'global_admins.admin1_code')
            ->orderBy('date')
            ->orderBy('commodity_name')
            ->get();
    }

返回的JSON对象数量超过50000个, 需要90秒左右的时间来完成加载, 我唯一想到的是把响应从JSON改成CSV(会不会有帮助), 因为前端库接受JSON和CSV的http响应, 如果有帮助请告诉我怎么做? 如果我需要一个第三方库?

请给我建议,我怎样才能使动作加载更快。

谢谢您的帮助。

SELECT `commodities`.`name` AS `commodity_name`,
       `price_types`.`name` AS `type_name`,
       `measure_units`.`name` AS `unit_name`,
       `global_admins`.`admin0_code` AS `admin0`,
       `global_admins`.`admin0_name` AS `country_name`,
       `global_admins`.`admin1_code` AS `admin1`,
       `global_admins`.`admin1_name` AS `governorate_name`,
       ROUND(AVG(CMP.price) / 1000, 3) AS price
FROM `commodities_monthly_prices` AS `CMP`
INNER JOIN `locations` ON `CMP`.`location_id` = `locations`.`id`
INNER JOIN `global_admins` ON `locations`.`admin0` = `global_admins`.`admin0_code`
INNER JOIN `commodities` ON `CMP`.`commodity_id` = `commodities`.`id`
INNER JOIN `price_types` ON `CMP`.`price_type_id` = `price_types`.`id`
INNER JOIN `measure_units` ON `CMP`.`measure_unit_id` = `measure_units`.`id`
WHERE `locations`.`admin0` = ?
GROUP BY `CMP`.`price_year`,
         `CMP`.`price_month`,
         `commodity_name`,
         `type_name`,
         `unit_name`,
         `global_admins`.`admin0_name`,
         `global_admins`.`admin0_code`,
         `global_admins`.`admin1_name`,
         `global_admins`.`admin1_code`
ORDER BY `commodity_name` ASC
mysql laravel performance api
1个回答
1
投票

首先, 你需要 INDEX(admin0) 关于 Locations.

你不需要一个以亿为单位的数据类型。 price_month int(10) unsigned DEFAULT NULL. INT 需要4个字节。TINYINT 只需要1个字节。 而其他很多列都比必要的大。 这对磁盘空间和查询速度都有影响。

如果这是一个 "年",我希望你不是把它比作一个INT。 str_year0 varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,

commodities_monthly_prices 既有价格,也有对商品的描述(市场、货币等)。 描述可能是不变的,所以可能应该放在一个单独的表中。

你的问题是关于加载的速度。 它是否来自CSV文件,通过 LOAD DATA? 如果是这样,我建议你将其加载到一个根据输入数据的样子而定制的表中。 然后对数据进行按摩 -- -- 归一化、清理、修正错别字等。 最后把数据复制到你要分析的表中。 这些表的形式不一定和原始数据一样。 例如,这将给你一个机会来拆解 commodities_monthly_prices.

在模式设计中,不允许有多个列代表一个数组。 我想到的是str_year,admin_name等。 由于我不明白它们的用途,所以我没有具体的建议,只能说我上面说的重组就是解决这个问题的时候。

你提到了JSON,但我在Schema中没有看到这样的内容。

© www.soinside.com 2019 - 2024. All rights reserved.