2017-08-19 3 views
1

Nous avons une table simple Redshift qui stocke les données de séries chronologiques semi-structurées:Rejoindre des événements de journaux associés dans Redshift?

  Table "public.system_log_lines" 
    Column |   Type    | Modifiers 
--------------+-----------------------------+----------- 
id   | bigint      | not null 
received_at | timestamp without time zone | not null 
program  | character varying(64)  | 
message  | character varying(65535) | 
Indexes: 
    "system_log_lines_new_pkey" PRIMARY KEY, btree (id) 

Son sortkey est received_at:

  table   | diststyle | sortkey1 | skew_sortkey1 
------------------------+-----------+-------------+--------------- 
system_log_lines  | EVEN  | received_at |   60.26 

Une question commune au sujet de ces données: « ce que les événements se produisent peu de temps après un type particulier d'événement inhabituel? ".

Exprimant ce type de question dans SQL est simple:

select 
    first_lines.received_at, 
    more_lines.* 
from (
    select 
     log.received_at, 
     log.program, 
     log.message 
    from system_log_lines as log 
    where 
     log.program = 'something.log' 
     and log.message like '%SOME INTERESTING STRING%' 
) as first_lines 
left join system_log_lines as more_lines on 
    more_lines.received_at between 
     first_lines.received_at 
     and first_lines.received_at + '1 minute'::interval 
; 

Cependant, Redshift est incapable d'exécuter cette requête avec succès. Il ne se termine jamais lors de la course dans la pratique. Voici le plan de requête produit:

               QUERY PLAN                 
----------------------------------------------------------------------------------------------------------------------------------------- 
XN Nested Loop Left Join DS_BCAST_INNER (cost=0.00..64217501937184.91 rows=2973033 width=237) 
    Join Filter: (("inner".received_at <= ("outer".received_at + '00:01:00'::interval)) AND ("inner".received_at >= "outer".received_at)) 
    -> XN Seq Scan on system_log_lines log (cost=0.00..401359.38 rows=1 width=8) 
     Filter: (((message)::text ~~ '%SOME INTERESTING STRING%'::text) AND ((program)::text = 'something.log'::text)) 
    -> XN Seq Scan on system_log_lines more_lines (cost=0.00..267572.92 rows=26757292 width=229) 
----- Nested Loop Join in the query plan - review the join predicates to avoid Cartesian products ----- 
(6 rows) 

La jointure est inefficace. Ce n'est pas surprenant étant donné la condition BETWEEN. Ce qui est est que la requête ne parvient toujours pas à se terminer même si un LIMIT 1 explicite est appliqué à la sous-sélection (c.-à-d. Qu'il n'y a qu'un seul "événement inhabituel" à joindre). Ou même si aucune ligne n'est renvoyée par cette sous-sélection (c.-à-d. Qu'il n'y a aucun événement auquel participer).

Cela semble bizarre puisque la même requête ne fin si l'JOIN est retirée, en utilisant des conditions received_at littérales, donc il semble que même une simple jointure de boucle imbriquée de mise en œuvre (par exemple, l'exécution de la boucle se joindre à la couche d'application) pourrait travailler de façon acceptable.

Existe-t-il un moyen de structurer ce type de requête de sorte que Redshift puisse l'exécuter avec succès?

Répondre

1

Vous pouvez utiliser lag():

select l.* 
from (select l.*, 
      lag(l.program) over (order by received_at) as prev_program, 
      lag(l.message) over (order by received_at) as prev_message, 
      lag(l.received_at) over (order by received_at) as prev_received_at 
     from from system_log_lines l 
    ) l 
where l.prev_program = 'something.log' and 
     l.prev_message like '%SOME INTERESTING STRING%'; 

fonctions de fenêtre doivent être beaucoup plus rapide que votre join. Vous pouvez vouloir une logique supplémentaire pour capturer la dépendance temporelle.