Reputation: 5905
I've a table of IP addresses. The table has two columns names starting_ip
and ending_ip
. The table looks like the following:
Now, let's say I have a random IP address. From that random Ip address, I want to know the city_name
. That means I need to know that the random IP address falls between which range, based on starting_ip
and ending_ip
. Then find 1 record and get the city_name
.
I wrote a query something like this:
class IpToCity < ActiveRecord::Base
establish_connection :"ip_database_#{Rails.env}"
scope :search_within_ip_range, -> (ip_address) do
self.connection.select_all("
with candidate as (
select * from ip_cities
where ending_ip >= '#{ip_address}'::inet
order by ending_ip asc
limit 1
)
select * from candidate
where starting_ip <= '#{ip_address}'::inet;
")
end
end
It's a scope, where I pass the random IP and get a single record. The problem is, the query works fine, but it's very slow. Any suggestion, how to make it faster?
Thanks in advance!
Upvotes: 1
Views: 469
Reputation: 45941
Do all the rows match this format?
starting_ip ending_ip
x.y.z.0 x.y.z.255
If so, then you can add another column for "prefix": x.y.z.
Then match the first 3 octets of the target against the prefix column.
When updating the DB, break rows that span more than one prefix into multiple rows.
The max number of rows is 16.8M (2563), which is small and only slightly bigger than your current 5M.
Upvotes: 2