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?
3 Réponses :
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%');
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.
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.
Merci pour votre contribution, je l'ai essayé mais ma requête initiale semble être plus rapide.
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
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.
Une sortie EXPLAIN?