Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

356
Vistas
Laravel - How to optimize MIN - MAX - orderBy queries?

My code in Laravel is:

Car::selectRaw('*,
    MIN(car_prices.price) AS min_price,
    MAX(car_prices.price) AS max_price,
    MAX(car_prices.updated_at) AS latest_update')
->leftJoin('car_prices', 'car_prices.car_id', 'cars.id')
->groupBy('car_prices.car_id')
->orderBy('latest_update', 'desc')
->paginate(10);

It takes long time to run until throwing error:

Maximum execution time of 60 seconds exceeded

The count of records in cars table is 100,000 and 6,000,000 in car_prices.

The tables structure:

CREATE TABLE `cars` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=110001 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

CREATE TABLE `car_prices` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `car_id` bigint(20) unsigned NOT NULL,
  `price` decimal(8,2) NOT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `car_prices_car_id_foreign` (`car_id`)
) ENGINE=MyISAM AUTO_INCREMENT=5506827 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

The query:

select count(*) as aggregate
    from `cars`
    left join `car_prices`
    on `car_prices`.`car_id` = `cars`.`id`
    group by `car_prices`.`car_id`;

select *,
    MIN(car_prices.price) AS min_price,
    MAX(car_prices.price) AS max_price,
    MAX(car_prices.updated_at) AS latest_update from `cars`
    left join `car_prices`
    on `car_prices`.`car_id` = `cars`.`id`
    group by `car_prices`.`car_id`
    order by `latest_update` desc
    limit 10
    offset 0;

How can I optimize it? Should I cache the data? Or there is some better query than this?

  • My hard disk is SSD
  • Value of innodb_flush_log_at_trx_commit = 1
  • The number of writes/inserts approximately 1000/second from 10AM - 02PM and before and after this period there are much less requests.
over 4 years ago · Santiago Trujillo
3 Respuestas
Responde la pregunta

0

U need to either have better car table unique index latest_update or remove ->orderBy('latest_update', 'desc') in query. and sort it after receiving the results

U can check the performance in mysql with explain

EXPLAIN SELECT * FROM car order by latest_update desc;

/// Check this https://www.exoscale.com/syslog/explaining-mysql-queries/#:~:text=the%20last%20decade.-,Explain,DELETE%20%2C%20REPLACE%20%2C%20and%20UPDATE%20.

and https://dev.mysql.com/doc/refman/5.7/en/using-explain.html#:~:text=The%20EXPLAIN%20statement%20provides%20information,%2C%20REPLACE%20%2C%20and%20UPDATE%20statements.&text=That%20is%2C%20MySQL%20explains%20how,joined%20and%20in%20which%20order.

Basically u need to optimize (better index) your DB table "car" so that it perform well

And other thing u might to try increasing execution time In php.ini u need to set max_execution_time = 600 or something more to just check how much time it needed to complete execution. https://www.codewall.co.uk/increase-php-script-max-execution-time-limit-using-ini_set-function/

over 4 years ago · Santiago Trujillo Denunciar

0

In both queries,

GROUP BY cars.id

This is instead of using car_prices.car_id, which might be missing because of the LEFT JOIN.

Once you have done that, the first query (with just the COUNT) can drop the JOIN. And then the GROUP BY becomes redundant:

select  count(*) as aggregate
    from  `cars`

The second query has issues.

With the current design, you must go through all of both tables. Ugh.

Also... If there are no prices for a given car, it will have NULL for latest_update, therefore it will sort at the end of the 100,000 rows. Given that, you may as well not display those cars; this would simplify the query enough to be better optimized.

If you need to list the cars for which you have no prices, make that a separate request in the UI. That query will be a LEFT JOIN .. IS NULL and won't need the MAX()s.

But, I am still concerned about the 10,000 pages that the user needs to paginate through.

Switch from MyISAM to InnoDB.

Toss created_at and updated_at, if you aren't using them for anything.

After that, cars is simply a mapping between id and name. This might allow you to avoid going through cars. Instead do something like

SELECT  ( SELECT name FROM cars WHERE id = x.car_id ) AS name, 
        ...
     FROM ...

Another thought that whenever you add a row to car_prices, you update updated_at in cars. This would allow you to find the 10 cars entirely in cars.

Decide what you are willing to sacrifice.

More

Note: With MyISAM, a slow SELECT blocks UPDATE. With InnoDB, the can run in parallel; the SELECT uses the values before the UPDATE. Either way, the select is at some "point in time". But InnoDB allows more parallelism.

It is a tradeoff. A small slowdown in updates to achieve a big speedup on selects. (No, I don't know for sure that my suggestion is "faster")

Some further questions to analyze the tradeoff:

  • Disk: HDD or SSD?
  • Value of innodb_flush_log_at_trx_commit (after you change to InnoDB).
  • How much traffic? As a first cut, is the number of writes--insert/delete--more than 100/second?
over 4 years ago · Santiago Trujillo Denunciar

0

The query you have used is not apt for such large tables. instead whenever entry coming to the table car_prices set a operation and take minimum and maximum value and store it in the cars table. or you can setup a crone for this.

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda