Question

I have to make my query on large database (Snort alerts) to find duplicate entries. However, I came up with bellow query, but it takes so many time to be executed!

SELECT sid, cid, timestamp, sig_name, inet_ntoa(ip_src), layer4_sport,
       inet_ntoa(ip_dst), layer4_dport
  FROM DB
 WHERE (ip_dst IN
        (SELECT ip_dst FROM DB GROUP BY ip_dst HAVING count(*) > 1)
   AND timestamp IN
        (SELECT timestamp FROM DB GROUP BY timestamp HAVING count(*) > 1)
   AND layer4_dport IN
        (SELECT layer4_dport FROM DB GROUP BY layer4_dport HAVING count(*)>1 ))

The above query trying to find alerts ip_dst that has same timestamp and layer4_dport if the they came more than one time. I hope its clear!

Any tips or tricks to make it efficient?

Was it helpful?

Solution

I've formatted your query... if we break it down you seem to be applying a couple of functions inet_ntoa. If you don't have a pressing need for then get rid of them ( especially if they look at a table ).

Secondly, if we look at your query you are doing a full scan of DB 3 times for your various counts, and then at the very minimum a range scan in your top level select.

SELECT sid, cid, timestamp, sig_name, inet_ntoa(ip_src), layer4_sport, inet_ntoa(ip_dst), layer4_dport 
  FROM DB 
 WHERE ( ip_dst IN ( SELECT ip_dst 
                       FROM DB 
                      GROUP BY ip_dst 
                     HAVING count(*) > 1 ) 
   AND timestamp IN ( SELECT timestamp 
                        FROM DB 
                       GROUP BY timestamp 
                      HAVING count(*) > 1 ) 
   AND layer4_dport IN ( SELECT layer4_dport 
                           FROM DB 
                          GROUP BY layer4_dport 
                         HAVING count(*) > 1 ) 
        ) 

By not linking your subquery back to the main table, you've assumed that ip_dst, timestamp and layer4_dport are each unique across the whole table and then are trying to find where the unlikely occurrence of 3 independently unique values happened to have duplicates in the same row.

I suspect what you want to do is something like the following:

SELECT a.sid, a.cid, a.ip_dst, a.timestamp, a.sig_name, a.layer4_sport, a.layer4_dport 
  FROM DB a 
  JOIN ( SELECT timestamp, layer4_dport 
           FROM DB 
          GROUP BY timestamp, layer4_dport
         HAVING count(*) > 1 ) b
    ON a.timestamp = b.timestamp
   AND a.layer4_dport = b.layer4_dport

This finds you all the rows where there are more than 1 identical timestamp and layer4_dport combinations as per your question.

If you want to find all the duplicates at the level of ip_dst then you need to add this to your sub-query.

OTHER TIPS

The link below could help you.

Find duplicate records in MySQL

I hope that this post can help you optimize your query.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top