模型中的大尺寸字段该在什么时候获取?
这里的大尺寸字段指的是 TEXT 或 BLOB 或更大内容尺寸的字段
起因#
我最近在写 Laravel 框架的 GraphQL 插件,目前在测试用例中简单实现了通过 graphql-php 和 dataloader-php 两个项目来查询数据的逻辑(实现方式非常简单粗暴,自己都看不下去)。但在数据的字段选择方面遇到了问题:在使用 DataLoader 来获取数据时,是否应该在一开始就全读出来( lighthouse 项目就是这样做的)?
介绍一下 DataLoader 项目#
DataLoader 的一个特点就是会缓冲数据到内存中,这点非常适合 GraphQL 这种查询协议,因为在接口路由入口上无法得知当前查询结果是否会被复用。好比客户端的一次查询中,请求一个订单列表,订单列表用户属性结果可能会重复, DataLoader 针对此种情况进行优化:将此过程抽象成通过一组 key 获取结果的过程,且通过 promise 结构延后执行,可大幅降低 GraphQL 中的重复查询问题和 N + 1 问题。
问题分析#
但 GraphQL 查询的字段是随请求变化的,如果严格按照每次请求的字段进行数据加载,那么一次查询的两个请求中,字段稍微改动一下,将造成结果无法复用。如果采用 lighthouse 项目那种固定加载全部字段的做法也会产生大量开销,严重的情况如果遇到大尺寸字段将可能导致内存超出限制错误。
我的尝试#
我目前采用的方法是:在试用 DataLoader 得时候将当时的查询字段同查询的 key 一起提交给 DataLoader 实例,并在进行数据加载逻辑之前,对字段进行去重合并:
$fields = array_keys(collect($keys)->pluck(1)->reduce(function ($a, $b) {
return array_merge($a, $b);
}, []));
这样只能从某种程度上解决问题,虽然规避了将所有字段查出的问题,也尽量解决了不同字段查询的数据复用问题,但如果少量查询中存在大尺寸字段,依然有可能一次性将所有数据的这类字段加载出来,消耗不必要的内存分配开销。
大家遇到这种情况都是怎么处理的?还请不吝赐教。
推荐文章: