J'ai besoin d'aide pour écrire/optimiser une requête pour récupérer la dernière version de chaque ligne par type et effectuer quelques calculs en fonction du type. Je pense que ce serait mieux si je l'illustre avec un exemple.Comment obtenir la ligne la plus récente par type et effectuer des calculs, en fonction du type de ligne?
Compte tenu de l'ensemble de données suivantes:
+-------+-------------------+---------------------+-------------+---------------------+--------+----------+
| id | event_type | event_timestamp | message_id | sent_at | status | rate |
+-------+-------------------+---------------------+-------------+---------------------+--------+----------+
| 1 | create | 2016-11-25 09:17:48 | 1 | 2016-11-25 09:17:48 | 0 | 0.500000 |
| 2 | status_update | 2016-11-25 09:24:38 | 1 | 2016-11-25 09:28:49 | 1 | 0.500000 |
| 3 | create | 2016-11-25 09:47:48 | 2 | 2016-11-25 09:47:48 | 0 | 0.500000 |
| 4 | status_update | 2016-11-25 09:54:38 | 2 | 2016-11-25 09:48:49 | 1 | 0.500000 |
| 5 | rate_update | 2016-11-25 09:55:07 | 2 | 2016-11-25 09:50:07 | 0 | 1.000000 |
| 6 | create | 2016-11-26 09:17:48 | 3 | 2016-11-26 09:17:48 | 0 | 0.500000 |
| 7 | create | 2016-11-27 09:17:48 | 4 | 2016-11-27 09:17:48 | 0 | 0.500000 |
| 8 | rate_update | 2016-11-27 09:55:07 | 4 | 2016-11-27 09:50:07 | 0 | 2.000000 |
| 9 | rate_update | 2016-11-27 09:55:07 | 2 | 2016-11-25 09:55:07 | 0 | 2.000000 |
+-------+-------------------+---------------------+-------------+---------------------+--------+----------+
Le résultat attendu devrait être:
+------------+--------------------+--------------------+-----------------------+
| sent_at | sum(submitted_msg) | sum(delivered_msg) | sum(rate_total) |
+------------+--------------------+--------------------+-----------------------+
| 2016-11-25 | 2 | 2 | 2.500000 |
| 2016-11-26 | 1 | 0 | 0.500000 |
| 2016-11-27 | 1 | 0 | 2.000000 |
+------------+--------------------+--------------------+-----------------------+
A la fin du poste est la requête qui est utilisée pour obtenir ce résultat. Je suis prêt à parier qu'il devrait y avoir un moyen de l'optimiser, car il utilise des sous-requêtes avec des jointures, et d'après ce que j'ai lu sur BigQuery, les jointures devraient être évitées. Mais d'abord un peu d'arrière-plan:
En résumé, l'ensemble de données représente une table d'ajout uniquement à laquelle sont écrits des événements multipaires. La taille des données est dans les centaines de millions et va atteindre des milliards +. Puisque les mises à jour dans BigQuery ne sont pas pratiques, et que les données sont transmises à BQ, j'ai besoin d'un moyen de récupérer le plus récent de chaque événement, d'effectuer des calculs basés sur certaines conditions et de retourner un résultat précis. La requête est générée dynamiquement, en fonction de l'entrée de l'utilisateur, ce qui permet d'inclure davantage de champs/calculs, mais a été omis pour plus de simplicité.
- Il n'y a qu'un seul événement
create
, maisn
de tout autre type - Pour chaque groupe d'événements, seul le dernier devrait être pris en compte lorsque vous faites les calculs.
- status_update - met à jour l'état
- rate_update - met à jour le taux
- créer - explicite
- Chaque événement qui ne
create
peut pas porter le reste des informations de mai/original ne pas être précis (sauf pour message_id et le champ sur lequel l'événement fonctionne) (l'ensemble de données est simplifié, mais imaginez qu'il y ait beaucoup plus de colonnes, et plus d'événements seront ajoutés plus tard)- E.g. un
rate_update
peut ou peut ne pas avoir l'ensemble du champ d'état, ou une valeur qui n'est pas la finale, donc pas de calcul peut être effectué sur le champ d'état d'un événementrate_update
et va de même pourstatus_update
- E.g. un
- Il peut Supposons que la table est partitionnée par date et que chaque requête utilisera les partions. Ces conditions ont été omises en faveur de la simplicité pour le moment.
Je suppose que j'ai quelques questions:
- Comment cette requête être optimisée? Sera-t-il préférable de placer les événements autres que
create
dans leurs propres tables, où les seuls champs disponibles seront ceux pertinents pour les événements, et nécessaires pour les jointures (message_id, event_timestamp)? Est-ce que cela réduira la quantité de données traitées? - Quelle serait la manière la plus optimale d'ajouter plus d'événements dans le futur, qui auront leurs propres conditions et calculs?
En fait, tout conseil sur la façon d'interroger ce jeu de données efficacement et amical est plus que bienvenu! Je vous remercie! :)
La monstruosité que j'ai trouvée est la suivante. Les INNER JOINS
sont utilisés pour récupérer la dernière version de chaque ligne, selon cette resource
select
sent_at as sent_at,
sum(submitted_msg) as submitted,
sum(delivered_msg) as delivered,
sum(sales_rate_total) as sales_rate_total
FROM (
#DELIVERED
SELECT
d.message_id,
FORMAT_TIMESTAMP('%Y-%m-%d 00:00:00', sent_at) AS sent_at,
0 as submitted_msg,
sum(if(status=1,1,0)) as delivered_msg,
0 as sales_rate_total
FROM `events` d
INNER JOIN
(
select message_id, max(event_timestamp) as ts
from `events`
where event_type = "status_update"
group by 1
) g on d.message_id = g.message_id and d.event_timestamp = g.ts
GROUP BY 1,2
UNION ALL
#SALES RATE
SELECT
s.message_id,
FORMAT_TIMESTAMP('%Y-%m-%d 00:00:00', sent_at) AS sent_at,
0 as submitted_msg,
0 as delivered_msg,
sum(sales_rate) as sales_rate_total
FROM `events` s
INNER JOIN
(
select message_id, max(event_timestamp) as ts
from `events`
where event_type in ("rate_update", "create")
group by 1
) f on s.message_id = f.message_id and s.event_timestamp = f.ts
GROUP BY 1,2
UNION ALL
#SUBMITTED & REST
SELECT
r.message_id,
FORMAT_TIMESTAMP('%Y-%m-%d 00:00:00', sent_at) AS sent_at,
sum(if(status=0,1,0)) as submitted_msg,
0 as delivered_msg,
0 as sales_rate_total
FROM `events` r
INNER JOIN
(
select message_id, max(event_timestamp) as ts
from `events`
where event_type = "create"
group by 1
) e on r.message_id = e.message_id and r.event_timestamp = e.ts
GROUP BY 1, 2
) k
group by 1
Vous pouvez également être intéressé par une demande de fonctionnalité similaire (https://code.google.com/p/google-bigquery/issues/detail?id=706). –