1
votes

Mysql. Comment sélectionner des utilisateurs dans la table du journal à l'aide de deux enregistrements de texte différents

J'ai une énorme table de log et j'ai besoin de récupérer des données pour les statistiques d'utilisation. disons que nous avons une table de journal:

SELECT 
     user_id
FROM 
    log
WHERE 
    action LIKE '%2018%'
AND 
    user_id IN (SELECT DISTINCT user_id FROM log WHERE(action LIKE '%IOs%' OR action LIKE '%Android%' ))
GROUP BY user_id

Existe-t-il un moyen de récupérer tous les identifiants d'utilisateurs qui utilisent d'anciennes applications mobiles (2018)?

Je l'ai fait d'une manière mais ce n'est pas efficace

| user_id | action            |
| 12345   | app: IOs          |
| 12345   | app_version: 2018 |
| 12346   | app: Android      |
| 12346   | app_version: 2019 |
| 12347   | app: Windows      |
| 12347   | app_version: 2019 |

Cette requête a pris environ une demi-heure en production.

Donc à la fin je veux avoir la liste des identifiants d'utilisateurs aussi efficace que possible car je rejoindrai également une autre table pour recevoir leurs emails. Quelles options ai-je?


1 commentaires

Une sortie EXPLAIN?


3 Réponses :


0
votes

Vous pouvez utiliser EXISTS :

SELECT l.*
FROM log l
WHERE EXISTS (SELECT 1 FROM log l1 WHERE l1.user_id = l.user_id AND l1.action LIKE '%2018%');


1 commentaires

J'ai essayé de l'exécuter, mais cela prend des années à fonctionner sur mon système de test, donc quelle que soit la sortie, il est beaucoup plus lent que ma requête. Mais encore, merci pour votre contribution.



1
votes

Vous pouvez utiliser l'agrégation:

SELECT l.user_id
FROM log l
WHERE l.action REGEXP '2018|IOs|Android'
GROUP BY l.user_id
HAVING SUM(l.action LIKE '%2018%') > 0 AND       -- at least one 2018
       SUM(l.action LIKE '%2018%') <> COUNT(*);  -- at least one other

Malheureusement, les comparaisons LIKE nécessitent d'analyser la table log . La seule façon de contourner ce problème serait d'utiliser un index de texte intégral.

Vous pouvez simplifier la logique pour:

SELECT l.user_id
FROM log l
WHERE l.action LIKE '%2018%' OR
      l.action LIKE '%IOs%' OR
      l.action LIKE '%Android%'
GROUP BY l.user_id
HAVING SUM(l.action LIKE '%2018%') > 0 AND       -- at least one 2018
       SUM(l.action LIKE '%2018%') <> COUNT(*);  -- at least one other

Je ne sais pas si REGEXP est (légèrement) plus rapide que trois LIKE s ou non.


1 commentaires

Merci pour votre contribution, je l'ai essayé mais ma requête initiale semble être plus rapide.



0
votes

Voici ma solution avec un LEFT JOIN . Je comprends que vous avez une grande table de journalisation, donc ce n'est peut-être pas la meilleure. J'ai également ajouté quelques enregistrements supplémentaires à tester:

En gros, j'utilise LEFT JOIN pour déplacer des données de colonnes en lignes afin que je puisse simplement filtrer avec WHERE .

Violon SQL: https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=9db538e59b3d265e4e8d8559762e79d4 p> XXX

Le résultat: (sélectionnez uniquement ceux avec iOS ou Android et ont la version 2018)

user_id
 12345
 12349


2 commentaires

Ai-je bien compris que vous avez utilisé la clause WITH pour émuler des données et dans mon cas avec des données réelles, je peux simplement utiliser l'instruction select avec ma table de journal? Si tel est le cas, cela prend également beaucoup de temps à s'exécuter :( Encore, merci pour votre aide.


@Vladk Ouais, vous n'avez besoin que de la partie SELECT pour exécuter et changer le nom de la table. Vous voudrez peut-être essayer la réponse de Gordon car il est beaucoup plus expérimenté avec SQL.