I'm somewhat new to laravel and working on my first full-stack laravel project. I've been trying to follow the best practices of laravel to help with better optimization and performance. In the dashboard area of my app, I noticed that the models on some of my pages have 253 counts and the view in my dashboard layout has 17 counts when I check the Laravel debugger stats [see image below].
In the image above, I have a country model that has 249 rows of all countries in the world (which are used as dropdown select for users to pick their countries), as well as a notification (this count varies per user).
From my knowledge so far, I know data like countries that rarely change can be cached but I'd like to know how many is too many when it comes to Models and Views count. So I can always watch out for those values, in case I find myself in situations where I can't use cache or before data is cached.
Thanks
That is fine, if you need to display 249 records from the table then you will have to pull 249 records (or models).
What is an issue is when you involve relationships and you come across issues such as the n+1 query prblem; which is described here: What is the "N+1 selects problem" in ORM (Object-Relational Mapping)?
Related
I started to develop a little Content Management System for two languages (de, en) that starts to grow bigger.
In that context, I have Posts and Pages (a bit like WordPress or actually just like WordPress). But I am also planning to add further content types like Reviews, Courses, Tutorials (Recipes) and maybe even E-Books that are purchasable.
All these objects would have in common that they are contentable, so they will be shown on the front end with their dedicated urls, like /posts/{slug} for posts, /{slug} for pages, /reviews/{slug} for reviews and so on.
On the backend, this means an auto save and revision system is offered for these content types.
So, this would leave us will the following options:
Single Table Inheritance (we would need to live with many null values) - not supported officially by Laravel, but there is a package.
Multi Table Inheritance (which is not supported in Laravel either)
Polymorphism which is supported
CMS solution (like craft CMS), which basically breaks up the logic in elements, entries, fields and so on, alternative approach would be drupal's node approach - out of scope I believe (I dont have 6-9 months time to write a CMS from the scratch)
Have on Table per Model and try to use as much logic as possible between the models by using Traits (current status, I don't like it that much...).
After some googling, searching here on stackoverflow and looking at other projects, I am thinking of the following structure:
contents table:
id
site_id
title
... (some more columns that are shared among all models)
contentable_type
contentable_id
posts
id
pages
id
home
courses
id
name
featured
difficulty
free
So, these tables would be linked to the contents table through a belongsTo relationship, and the content model would define the morphable relationship.
class Content extends Eloquent {
public function contentable(){
return $this->morphTo();
}
}
class Post extends Eloquent (or Content) {
public function content(){
return $this->morphOne('Content', 'contentable');
}
}
Working with models would mean you would always have to load the content relationships.
Sorting & Ordering must be performed by joins.
And when creating, of course, we have to first create the content type model and then save and attribute it to a content model.
I never implemented a system with that kind of (sub) logic before, and it feels a bit odd to me to have a posts table with just an id (same would be true for other content types e.g. "abouts" in case they don't have extra columns), but I think it would be the "Laravel way" to solve this issue, right?
I believe STI wouldn't work for this case, and it is also a bit against Laravel's Eloquent pattern.
Has somebody already experiences with this approach? Am I on the right track here?
Note: I got inspired by the discussion here: How can I implement single table inheritance using Laravel's Eloquent?
In case anyone finds this question. I finally decided against this approach, basically because I believe it is not worth the efforts (and also most of the packages won’t work out of the box).
It is a much better approach to use Traits et cetera to reuse as much logic as possible and follow the Eloquent ORM approach.
So I'm just about at my whit's end here. I've been tasked with optimizing a system because pages are loading too slowly. The system is built on Laravel 5.5 (yeah I know not the latest version, but that's a problem for another day). I've installed Clockwork to get a better feel for what could be causing things to be so slow and literally fell off my seat. The load of a single page generated 10412 queries in the database (you read that right, 10000 queries to load a single page)!!!!!
Anyway, I tweaked relationships so that things could be properly lazy/eager loaded when necessary and that divided things by three... but that's still a lot considering how little information is currently displayed.
So I went on to try and tackle another problem they have: They defined custom attributes inside models that fetch informations from three or four layers of relationships. Here's a "simple" example:
ride-->(departureStop, destinationStop)-->(state, event, city)
This path is to resolve the "getNameAttribute()" defined inside the Ride model. So in essence, Laravel generates 5 queries just to calculate the name of a ride (said name being something like "Ottawa, On to Toronto, On"). Of course, being an attribute, this means that we get those 5 queries FOR EVERY INSTANCE OF THE RIDE MODEL. And that's just one attribute, there are dozens of them just like this.
Oh and just to add to the fun, we're also using the compoship package because some tables have composite primary keys.
I'm not sure what to include in terms of code here since everything is such tangled mess but every suggestion you can throw at me will be more than welcome.
I am calculating basketball stats and have the models Stat, User (which the basketball players are held within), Team, Stat_Meta, Game, Season, Substitution.
I have a view called statTable that can be added to any other view on the app. statTable basically just iterates through each player on the team and retrieves the calculation for each stat type (found in Stat_Meta model). Within those calculation, there are queries run for the Stat, Game, Season, etc. tables. By the time it iterates through every player and all their stats, we are looking at like 500 queries PER game (often we are going through like ~30 queries/view, so you do the math, it's bad).
My question: With the Laravel debug bar installed, I can see that in my test environment, I've got 3,116 queries running when loading the front page, and 2,432 of them are duplicates. It takes forever to load as well. So, how can I re-work this system of queries to reduce the number of them?
Full disclosure, I'm not a CS person, so efficiency isn't something I'm trained in. Right now, I'm super happy this even works, but not it is going to cost me an arm and a leg to do all these queries at scale (not to mention horrible UX).
You could do some optimization of your queries by using Laravel's eager loading. Definition of eager loading from official documentation:
When accessing Eloquent relationships as properties, the relationship
data is "lazy loaded". This means the relationship data is not
actually loaded until you first access the property. However, Eloquent
can "eager load" relationships at the time you query the parent model.
Eager loading alleviates the N + 1 query problem.
You can read some great examples from the link I provided. I believe this will optimize your queries a lot.
Beside eager loading, you should always aim to accomplish as much as you can with your queries instead of processing data with PHP, Laravel collections, etc.
When running SELECT queries it seems as if Yii is often performing each one twice. The first is a COUNT() and the second is the actual query.
What is causing this? It seems terribly inefficient.
In a related note, why does Yii perform a SHOW COLUMNS FROM and SHOW CREATE TABLE so often? Doesn't setting up a relation within the Model tell Yii enough about the schema?
I assume you are using active records a lot in conjunction with listing widgets such as CGridView and CListView.
What is causing this? It seems terribly inefficient.
Well, in order for the pagination to work in CListView and CGridView, the assigned CActiveDataProvider (or actually any data provider) needs to fetch the total item count. This won't work with the result set which usually has a LIMIT clause applied. Hence, an additional COUNT() is performed to retrieve said number.
In a related note, why does Yii perform a SHOW COLUMNS FROM and SHOW CREATE TABLE so often? Doesn't setting up a relation within the Model tell Yii enough about the schema?
No. Yii does far more than managing related models. Part of the AR abstraction layer is also to determine which fields are available in a table and hence can be accessed on a model representing a table row. However, you don't have to live with this as schemata can be cached conveniently. To do so, follow these steps:
Configure a caching component such as CApcCache in your protected/config/main.php in the components stanza.
Change the configuration of your db component so it contains the following lines:
'schemaCacheId'=>'cache', // This is the name of the cache component you
// configured in step 1. It's also the default value.
'schemaCacheDuration'=>3600, // Cache table schemata for an hour.
// Set this higher if you like.
A word of advice; don't do this in your development environment: If your database design changes, AR models might not reflect this due to stale caches.
I'm currently creating my own PHP mvc for a site that I run so that it will include just the code needed yo be as light and fast as possible.
The site has quite a large range of functions and user features so working out which actions go where in which models controlled by which controllers is starting to get quite complex.
Example
Say I have the following member features
Favourites
Friends
History
Each of those can be controlled by the membercontroller but then my question is whether to have them all inside one model or a model for each.
Each of those three has sub many actions such as:
Add to favourites
Remove favourites
Show favourites
Add to history
Remove history
Show history
Add as friend
Remove friend
Message friend
...etc
At the moment I'm thinking a model for each (favourite, friends, history) is probably the best way, but can it get to a point where you have too many models?
At the moment the whole site has 6 controllers, 17 models and 25 views
Yes you can technically have too many models, there is a limit (as always) of how many classes can exist in PHP. But it's pretty large, so keep on going. You can not only have many but also different kind of models at once. So keep on going, don't restrain your coding by thinking there might be a limit you don't see so far.
So not the count of files, but how nicely written your code is, e.g. is everything grouped properly that belongs together? See as well Domain Model.
I suggest you let ModelController deal with actions that somehow modify Model.
I.e. FavoritesController deals with adding, removing and showing favorites (stored on FavoritesModel). Keeps your controllers lean/slim, is a lot easier to test (less methods) and keeps logical app parts together.
Also, you could divide the application into smaller apps that deal each with:
Auth/Login
Social/Sharing
add/read/show articles (main app)
In such scenarios there is no "right" answer, so all I can give you is my own interpretation. I would use a service to do bind one or more models together. So, a User service would use the User model and the Favourite model to manipulate and display user favourites.