Description
- Laravel Version: 6.14.0
- Nova Version: 2.10.1
- PHP Version: 7.3.14
Description:
Hello,
I've installed Nova on one of our projects which has quite a large dataset. It seems like we can't properly optimize the database queries that are being run by Nova. To demonstrate the issue, let's assume we have a few models:
- User - (We have well over 1M users)
- Post
- Tip
- Comment (
user_id
,commentable_type
,commentable_id
)
The relationships:
- User
hasMany
Comment - Tip
morphToMany
Comment - Post
morphToMany
Comment
The Comment
resource's fields are:
public function fields(Request $request)
{
return [
ID::make()->sortable(),
BelongsTo::make('User')->searchable()->readonly(),
MorphTo::make('Commentable')->types([
Tip::class,
Post::class,
])->searchable(),
Textarea::make('Body'),
];
}
The Issue
There are a few issues in this scenario.
-
Making the
User
fieldreadonly()
did not prevent the request to fetch every user in the system in order to populate the select box (which is disabled). We had to "fake" it and add thesearchable()
property in order for it to not select all users. It would be nice if it respected thereadonly()
flag and did not issue a request to populate the select box with every single user but just the one currently selected. -
There seems to be no way I can control what the
BelongsTo
searchable() autocomplete's query:
2.1. Ideally, since we have so many users and each user record is packed with lot of data, I would not want to do a simpleselect *
but rather choose the columns I know that we are going to need. For example, select only theid
,username
, andfirst_name
columns. This speeds up the query significantly. I tried to achieve that using therelatableUser
method but it seems like it ignored myselect()
call there. We tried leveraging the$with
field ($with = ['user:id,username,first_name']
), but it seems to only affect the index page.
This issue is even worse when we try to fetchPost
from an autocomplete since it has a huge body which slows down the query significantly when we fetch many posts.
2.2. When I type into the autocomplete, the system runs a query that matches the index page's query. It will execute a like
query against all columns specified in the $search
property of the User
resource. We know that whenever we search for a user from an autocomplete, we always want to search by its id
or by its username
. We thought that we could override the default query's filters in the relatableUser
method, but we couldn't. When we tried doing so, it seemed like our where
clauses were simply appended to the query. At the moment the Autocomplete is basically unusable for us; it takes over 15 seconds to get some results
- Eager loading polymorphic relationships - on our
Comment
resource, we want to eager load thecommentable
relationship. TheCommentable
objects have many redundant fields that are never used in the index page or any other place which are slowing the query significantly. I tried to leverage the$with
property (just like I did with theuser
relationship) and pass a callback to it so I can choose which fields I want for each commentable object, but we get an error that we an expression is not allowed as a default value:
public static $with = [
'user:id,username,first_name',
'commentable' => function (MorphTo $morphTo) {
$morphTo->morphWith([Post::class => 'id,title', Tip::class => 'id,title']);
},
];
It seems like we are struggling to optimize the system to work with very large datasets.
Are we missing something?