1
votes

Sélection des données pour qu'elles ne renvoient que la dernière ligne par ID

Je travaille actuellement sur mon premier projet Laravel et je travaille avec une base de données qui contient des lignes comme celle-ci:

id       message    timestamp

1        fourth     1530000000
2        second     1510000000 
3        first      1500000000 
4        fourth     1530000000 
5        second     1510000000 
6        first      1500000000 
7        first      1500000000 

(données factices). Je souhaite créer une requête SQL qui renvoie le dernier message en fonction de l'horodatage le plus élevé. Donc, par exemple, si nous regardons le premier identifiant, je veux qu'il renvoie quatrième car l'horodatage connecté à ce message est supérieur à tout autre enregistrement avec id = 1 .

La raison pour laquelle je souhaite n'avoir qu'une seule requête pour chaque identifiant est que plus je dois exécuter de requêtes, plus il faut de temps pour exécuter la page, ce qui rend l'expérience utilisateur assez médiocre.

J'ai essayé plusieurs choses que j'ai lues en ligne, mais en vain. J'ai essayé d'utiliser DISTINCT , GROUP BY et quelques requêtes construites par des questions que j'ai rencontrées. J'ai également jeté un œil à la documentation de Laravel mais je n'arrive tout simplement pas à la faire fonctionner.

$data = \DB::table('data')
         ->distinct()
         ->get();

J'ai essayé des choses comme celle-ci, mais maintenant que j'y pense renvoie probablement simplement les combinaisons uniques d'identifiant, de message et d'horodatage.

En fin de compte, j'aimerais obtenir quelque chose comme ceci:

id       message    timestamp

1        first      1500000000 
1        second     1510000000
1        third      1520000000
1        fourth     1530000000
2        first      1500000000 
2        second     1510000000 
3        first      1500000000 
4        first      1500000000 
4        second     1510000000  
4        third      1520000000 
4        fourth     1530000000 
5        first      1500000000 
5        second     1510000000 
6        first      1500000000 
7        first      1500000000 

Quoi qu'il en soit, je apprécierait vraiment que quelqu'un sache comment résoudre mon problème.

P.S. Pour une raison quelconque, chaque requête que j'exécute prend environ 2 secondes pour renvoyer les données (vu cela dans l'extension Laravel Debugger). Cela pourrait-il être dû à la grande quantité d'enregistrements dans le tableau (3926714)? Et est-ce que quelqu'un sait peut-être comment réduire le temps nécessaire?


0 commentaires

3 Réponses :


2
votes

Essayez de regrouper par identifiant puis triez par horodatage. Ensuite, récupérez le message

\DB::table('data')->groupBy('id')->orderBy('timestamp')->first()->message

Edit: Si votre table est énorme et augmente considérablement et que vous n'avez besoin que du message, essayez de l'exécuter via SQL brut au lieu d'utiliser eloquent pour des performances rapides.


12 commentaires

J'obtiens une erreur lorsque j'utilise votre code. SQLSTATE [42000]: Erreur de syntaxe ou violation d'accès: 1055 'BootLogging.ycl_loggingdata.idlog' n'est pas dans GROUP BY (SQL: sélectionnez * dans le groupe `ycl_loggingdata` par` idobject` order by `timestampsec` asc limit 1 ) . Je ne sais pas si c'est pertinent mais le tableau contient plus de colonnes que les 3 que j'ai énumérées ci-dessus. Les trois que j'ai énumérés sont les seuls pertinents.


mettez à jour les paramètres MySQL sur config> database.php, puis ajustez MySQL strict sur 'strict' => false


Juste fait ça, ça a marché! cependant, cela semble prendre 21 secondes avant que j'aie mes données, à la fois avec la méthode Eloquent et la manière SQL brute. Connaissez-vous un moyen de réduire le temps que cela prend?


Je ne peux rien dire à ce sujet sans voir votre requête SQL.


La requête est \ DB :: select (DB :: raw ('SELECT idobject, message, timestampsec FROM ycl_loggingdata GROUP BY idobject')); Cela a pris 22,4 s ( prntscr.com/nxu2mj )


Votre requête semble incorrecte, cela ne donnera pas la réponse comme dans votre question, ni ma réponse n'est en aucun cas liée à votre requête SQL.


L'ajout d'un endroit a considérablement réduit le temps nécessaire, c'est bien. Le seul problème est qu'il a encore fallu 3s et que je dois faire 3 de ces requêtes pour que ce soit toujours très lent. SELECT idobject, message, timestampsec FROM ycl_loggingdata WHERE idlogdefinitie = 2 GROUP BY idobject est ce que j'ai en ce moment. Pensez-vous que l'indexation de la base de données accélérerait les choses?


Votre requête n'a renvoyé qu'une seule ligne, j'ai déclaré que j'avais besoin d'une ligne pour chaque ID. Quant à l'ordre par, ce n'était pas vraiment pertinent car je suis juste en train de parcourir les disques et de ne pas les imprimer comme ça.


créer une salle et inviter à discuter, partagera les détails là-bas.


Apparemment, je ne peux pas encore créer de salles, j'ai besoin de 100 points de réputation pour cela.


Pouvez-vous créer une pièce?


Très bien, donc je l'ai presque cloué au résultat que je veux. C'est la requête que j'ai actuellement prntscr.com/nxvz71 . Le fait est que l'enregistrement qu'il renvoie a le plus petit horodatage, et je veux qu'il soit le plus élevé. Une idée pour réparer ceci?



0
votes

Vous pouvez faire quelque chose comme ceci: DB :: table ('votre-table') -> orderby ('id', DESC) -> orderby ('message', ASC) -> get ();


3 commentaires

J'ai oublié. Vous pouvez également ajouter distinct à la requête pour obtenir l'identifiant distinct


Cette approche a dépassé la période de 60 secondes, donc je ne suis pas sûr que ce soit la manière la plus optimale.


Dans ce cas, vous pouvez travailler sur votre table afin de pouvoir implémenter des relations. Je pense qu'avec ça je serai rapide



0
votes

Auto JOIN

 $sql = "SELECT t1.* FROM data t1 JOIN ( SELECT id, MAX(timestamp) as max_created FROM data GROUP BY id ) t2 ON t1.`id` = t2.`id` AND t1.`timestamp` = t2.`max_created`";

 $rows= DB::select($sql);
 dd($rows);


0 commentaires