Home All Groups Group Topic Archive Search About
Author
30 Jun 2005 3:27 PM
Kathy
Hi All again

I have a question on an index

The query is as follows

SELECT  *
FROM dbo.IP_Addr_Work AS iaw LEFT JOIN dbo.IP_Address_City_Lkp AS iacl
  ON iaw.IPAddress BETWEEN iacl.IP_Address_From AND iacl.IP_Address_To

What index is more efficient

CLUSTERED INDEX ON IP_Address_From
and
CLUSTERED INDEX ON IP_Address_To

OR

CLUSTERED INDEX ON ( IP_Address_From , IP_Address_To)

Your help would be much appreciated

Thanks
Kathryn

Author
30 Jun 2005 3:59 PM
Ray
A table can only have 1 clustered index.
Because your doing a left join it may not efficiently use whatever index you
create.

as a rule of thumb You want to keep your clustered indexes smaller. Not
knowing the datatype of the the ip_Address_From, and IP_Address_To columns
its hard to say.
It won't hurt to have a nonclustered index on  ( IP_Address_From ,
IP_Address_To)
But you need to evaluate your indexes on dbo.IP_Addr_Work also.

Try using the index tuning wizard, and or reviewing your Execution plan.

Show quote
"Kathy" wrote:

> Hi All again
>
> I have a question on an index
>
> The query is as follows
>
> SELECT  *
> FROM dbo.IP_Addr_Work AS iaw LEFT JOIN dbo.IP_Address_City_Lkp AS iacl
>   ON iaw.IPAddress BETWEEN iacl.IP_Address_From AND iacl.IP_Address_To
>
> What index is more efficient
>
> CLUSTERED INDEX ON IP_Address_From
> and
> CLUSTERED INDEX ON IP_Address_To
>
> OR
>
> CLUSTERED INDEX ON ( IP_Address_From , IP_Address_To)
>
> Your help would be much appreciated
>
> Thanks
> Kathryn
>
>
>
Author
30 Jun 2005 4:00 PM
David Gugick
Kathy wrote:
Show quote
> Hi All again
>
> I have a question on an index
>
> The query is as follows
>
> SELECT  *
> FROM dbo.IP_Addr_Work AS iaw LEFT JOIN dbo.IP_Address_City_Lkp AS iacl
>  ON iaw.IPAddress BETWEEN iacl.IP_Address_From AND iacl.IP_Address_To
>
> What index is more efficient
>
> CLUSTERED INDEX ON IP_Address_From
> and
> CLUSTERED INDEX ON IP_Address_To
>
> OR
>
> CLUSTERED INDEX ON ( IP_Address_From , IP_Address_To)
>
> Your help would be much appreciated
>
> Thanks
> Kathryn

Could you tell us what columns you really need back from that tables.  I
can only assume you are not really wanting to pull in all rows from both
tables. Also, is that the only join condition:

"iaw.IPAddress BETWEEN iacl.IP_Address_From AND iacl.IP_Address_To"

Or is there some other column or set of columns that join these tables.
Could you also post the table DDL and explain what the query is supposed
to do.



--
David Gugick
Quest Software
www.imceda.com
www.quest.com
Author
30 Jun 2005 5:25 PM
Gert-Jan Strik
Kathy,

Neither index is likely be really speed up the query.

If you only need one (or two) columns from table IP_Address_City_Lkp
(for each IP_Addr_Work.IPAddress) instead of all columns, then there
might be a (much) more efficient way of writing the query.

If that is what you needs, then please post back what you really need.

Gert-Jan


Kathy wrote:
Show quote
>
> Hi All again
>
> I have a question on an index
>
> The query is as follows
>
> SELECT  *
> FROM dbo.IP_Addr_Work AS iaw LEFT JOIN dbo.IP_Address_City_Lkp AS iacl
>   ON iaw.IPAddress BETWEEN iacl.IP_Address_From AND iacl.IP_Address_To
>
> What index is more efficient
>
> CLUSTERED INDEX ON IP_Address_From
> and
> CLUSTERED INDEX ON IP_Address_To
>
> OR
>
> CLUSTERED INDEX ON ( IP_Address_From , IP_Address_To)
>
> Your help would be much appreciated
>
> Thanks
> Kathryn
Author
1 Jul 2005 5:41 AM
Kathy
Hi Guys

Thanks for the input.
If you can give me a more efficient way of doing this as well I would really
appreciate it

ok here is the scenario

We have a lookup table with IP addresses and Countries
These IP addresses are converted to an IP number and they exist in a range
i.e. IP_TO 680000        IP_From 680100

We have a table with a list of our users IPs
We convert the IP addresses in the users tables to a number

Then we have to join the user table to the Lookup table to map the IP's to
the countries because we need a list of all IP's with their countries

The join I have is the only join I need to make but because it is a range
one has to use between which may not be the best way to do this
Keep in mind however that the list of user IP's is 11 million plus so the
table is huge and we really need an effcient way to do this whether it is
via an index or something else

Here are the DDL's


CREATE TABLE [IP_Addr_Work] (
[IPAddressId] [int] NOT NULL ,
[IPNumber] [bigint] NULL ,
[IPAddress] [char] (20) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[IPStatus] [int] NULL
) ON [PRIMARY]

CREATE TABLE [IP_Address_City_Lkp] (
[IP_Address_From] [bigint] NOT NULL ,
[IP_Address_To] [bigint] NOT NULL ,
[Country_Short] [char] (2) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[Country_Long] [varchar] (64) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[Region] [varchar] (128) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[City] [varchar] (128) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
) ON [PRIMARY]

This is the join I need to do

SELECT iaw.IPAddressId, iaw.IPAddress, iaw.IPStatus
  , IPNumber , iacl.Country_Short, iacl.Country_Long, iacl.Region, iacl.City
FROM StagingDatabase.dbo.IP_Addr_Work AS iaw
LEFT JOIN dbo.IP_Address_City_Lkp AS iacl
  ON IPNumber BETWEEN iacl.IP_Address_From AND iacl.IP_Address_To








Show quote
"Kathy" <r**@roo.com> wrote in message
news:VsudnXBMv5fwklnfRVn-rw@is.co.za...
> Hi All again
>
> I have a question on an index
>
> The query is as follows
>
> SELECT  *
> FROM dbo.IP_Addr_Work AS iaw LEFT JOIN dbo.IP_Address_City_Lkp AS iacl
>  ON iaw.IPAddress BETWEEN iacl.IP_Address_From AND iacl.IP_Address_To
>
> What index is more efficient
>
> CLUSTERED INDEX ON IP_Address_From
> and
> CLUSTERED INDEX ON IP_Address_To
>
> OR
>
> CLUSTERED INDEX ON ( IP_Address_From , IP_Address_To)
>
> Your help would be much appreciated
>
> Thanks
> Kathryn
>
Author
1 Jul 2005 6:46 AM
David Gugick
Kathy wrote:
Show quote
> Hi Guys
>
> Thanks for the input.
> If you can give me a more efficient way of doing this as well I would
> really appreciate it
>
> ok here is the scenario
>
> We have a lookup table with IP addresses and Countries
> These IP addresses are converted to an IP number and they exist in a
> range i.e. IP_TO 680000        IP_From 680100
>
> We have a table with a list of our users IPs
> We convert the IP addresses in the users tables to a number
>
> Then we have to join the user table to the Lookup table to map the
> IP's to the countries because we need a list of all IP's with their
> countries
> The join I have is the only join I need to make but because it is a
> range one has to use between which may not be the best way to do this
> Keep in mind however that the list of user IP's is 11 million plus so
> the table is huge and we really need an effcient way to do this
> whether it is via an index or something else
>
> Here are the DDL's
>
>
> CREATE TABLE [IP_Addr_Work] (
> [IPAddressId] [int] NOT NULL ,
> [IPNumber] [bigint] NULL ,
> [IPAddress] [char] (20) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
> [IPStatus] [int] NULL
> ) ON [PRIMARY]
>
> CREATE TABLE [IP_Address_City_Lkp] (
> [IP_Address_From] [bigint] NOT NULL ,
> [IP_Address_To] [bigint] NOT NULL ,
> [Country_Short] [char] (2) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
> [Country_Long] [varchar] (64) COLLATE SQL_Latin1_General_CP1_CI_AS
> NULL , [Region] [varchar] (128) COLLATE SQL_Latin1_General_CP1_CI_AS
> NULL , [City] [varchar] (128) COLLATE SQL_Latin1_General_CP1_CI_AS
> NULL ) ON [PRIMARY]
>
> This is the join I need to do
>
> SELECT iaw.IPAddressId, iaw.IPAddress, iaw.IPStatus
>  , IPNumber , iacl.Country_Short, iacl.Country_Long, iacl.Region,
> iacl.City FROM StagingDatabase.dbo.IP_Addr_Work AS iaw
> LEFT JOIN dbo.IP_Address_City_Lkp AS iacl
>  ON IPNumber BETWEEN iacl.IP_Address_From AND iacl.IP_Address_To
>
>
How do you convert the IP address to a number. Just curious. What
indexing options have you tested thus far and what did the execution
plans show? Given your query, the big 11M row table is going to scan
every time since you are returning all rows from that table. Try one
composite clustered index on the IP Address From/To columns and see what
comes back in the execution plan.

--
David Gugick
Quest Software
www.imceda.com
www.quest.com
Author
1 Jul 2005 7:31 AM
Kathy
I am going to work on some other execution plans
Do you have a more efficient way of doing that join perhaps besides and
index ???
pehaps something else I could do besides a between

Here you go - this is how the IP is converted

-- Convert IP address in the form www.xxx.yyy.zzz into an IP
-- number according to the formula:
-- IP Number = 16777216*www + 65536*xxx + 256*yyy + zzz     (1)

CREATE FUNCTION dbo.udf_IP_Adress_to_IP_Number (@IP_Address CHAR(20))

RETURNS BIGINT
AS
BEGIN
  DECLARE @IP_Number BIGINT
  SELECT @IP_Number = CONVERT(BIGINT, SUBSTRING(@IP_Address, 1,
CHARINDEX('.', @IP_Address) - 1)) * 16777216
  SELECT @IP_Address = SUBSTRING(@IP_Address, CHARINDEX('.', @IP_Address) +
1, 12)
  SELECT @IP_Number = @IP_Number + CONVERT(BIGINT, SUBSTRING(@IP_Address, 1,
CHARINDEX('.', @IP_Address) - 1)) * 65536
  SELECT @IP_Address = SUBSTRING(@IP_Address, CHARINDEX('.', @IP_Address) +
1, 12)
  SELECT @IP_Number = @IP_Number + CONVERT(BIGINT, SUBSTRING(@IP_Address, 1,
CHARINDEX('.', @IP_Address) - 1)) * 256
  SELECT @IP_Address = SUBSTRING(@IP_Address, CHARINDEX('.', @IP_Address) +
1, 12)
  SELECT @IP_Number = @IP_Number + CONVERT(BIGINT, @IP_Address)
  RETURN @IP_Number
END



Show quote
"David Gugick" <david.gugick-nospam@quest.com> wrote in message
news:%23sIqjigfFHA.2644@TK2MSFTNGP09.phx.gbl...
> Kathy wrote:
>> Hi Guys
>>
>> Thanks for the input.
>> If you can give me a more efficient way of doing this as well I would
>> really appreciate it
>>
>> ok here is the scenario
>>
>> We have a lookup table with IP addresses and Countries
>> These IP addresses are converted to an IP number and they exist in a
>> range i.e. IP_TO 680000        IP_From 680100
>>
>> We have a table with a list of our users IPs
>> We convert the IP addresses in the users tables to a number
>>
>> Then we have to join the user table to the Lookup table to map the
>> IP's to the countries because we need a list of all IP's with their
>> countries
>> The join I have is the only join I need to make but because it is a
>> range one has to use between which may not be the best way to do this
>> Keep in mind however that the list of user IP's is 11 million plus so
>> the table is huge and we really need an effcient way to do this
>> whether it is via an index or something else
>>
>> Here are the DDL's
>>
>>
>> CREATE TABLE [IP_Addr_Work] (
>> [IPAddressId] [int] NOT NULL ,
>> [IPNumber] [bigint] NULL ,
>> [IPAddress] [char] (20) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
>> [IPStatus] [int] NULL
>> ) ON [PRIMARY]
>>
>> CREATE TABLE [IP_Address_City_Lkp] (
>> [IP_Address_From] [bigint] NOT NULL ,
>> [IP_Address_To] [bigint] NOT NULL ,
>> [Country_Short] [char] (2) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
>> [Country_Long] [varchar] (64) COLLATE SQL_Latin1_General_CP1_CI_AS
>> NULL , [Region] [varchar] (128) COLLATE SQL_Latin1_General_CP1_CI_AS
>> NULL , [City] [varchar] (128) COLLATE SQL_Latin1_General_CP1_CI_AS
>> NULL ) ON [PRIMARY]
>>
>> This is the join I need to do
>>
>> SELECT iaw.IPAddressId, iaw.IPAddress, iaw.IPStatus
>>  , IPNumber , iacl.Country_Short, iacl.Country_Long, iacl.Region,
>> iacl.City FROM StagingDatabase.dbo.IP_Addr_Work AS iaw
>> LEFT JOIN dbo.IP_Address_City_Lkp AS iacl
>>  ON IPNumber BETWEEN iacl.IP_Address_From AND iacl.IP_Address_To
>>
>>
> How do you convert the IP address to a number. Just curious. What indexing
> options have you tested thus far and what did the execution plans show?
> Given your query, the big 11M row table is going to scan every time since
> you are returning all rows from that table. Try one composite clustered
> index on the IP Address From/To columns and see what comes back in the
> execution plan.
>
> --
> David Gugick
> Quest Software
> www.imceda.com
> www.quest.com
Author
1 Jul 2005 3:23 PM
David Gugick
Kathy wrote:
Show quote
> I am going to work on some other execution plans
> Do you have a more efficient way of doing that join perhaps besides
> and index ???
> pehaps something else I could do besides a between
>
> Here you go - this is how the IP is converted
>
> -- Convert IP address in the form www.xxx.yyy.zzz into an IP
> -- number according to the formula:
> -- IP Number = 16777216*www + 65536*xxx + 256*yyy + zzz     (1)
>
> CREATE FUNCTION dbo.udf_IP_Adress_to_IP_Number (@IP_Address CHAR(20))
>
> RETURNS BIGINT
> AS
> BEGIN
>  DECLARE @IP_Number BIGINT
>  SELECT @IP_Number = CONVERT(BIGINT, SUBSTRING(@IP_Address, 1,
> CHARINDEX('.', @IP_Address) - 1)) * 16777216
>  SELECT @IP_Address = SUBSTRING(@IP_Address, CHARINDEX('.',
> @IP_Address) + 1, 12)
>  SELECT @IP_Number = @IP_Number + CONVERT(BIGINT,
> SUBSTRING(@IP_Address, 1, CHARINDEX('.', @IP_Address) - 1)) * 65536
>  SELECT @IP_Address = SUBSTRING(@IP_Address, CHARINDEX('.',
> @IP_Address) + 1, 12)
>  SELECT @IP_Number = @IP_Number + CONVERT(BIGINT,
> SUBSTRING(@IP_Address, 1, CHARINDEX('.', @IP_Address) - 1)) * 256
>  SELECT @IP_Address = SUBSTRING(@IP_Address, CHARINDEX('.',
> @IP_Address) + 1, 12)
>  SELECT @IP_Number = @IP_Number + CONVERT(BIGINT, @IP_Address)
>  RETURN @IP_Number
> END
>

I think you need to test the index and current design before making any
decisions about another solution.

--
David Gugick
Quest Software
www.imceda.com
www.quest.com
Author
1 Jul 2005 7:42 PM
Gert-Jan Strik
Hi Kathy,

I suspected a scenario like this, that is why I asked extra info.

Based on your narrative I will assume that the IP_From-IP_To are
nonoverlapping ranges. In other words, I'm assuming that a particular
will only have one (or zero) matches in the lookup table. The solution
below depends on this assumption.

The trick to use, is to rewrite the BETWEEN predicate (which forces
SQL-Server to scan half the index for each row) to a lookup of the
nearest value (which means only a few logical reads for each row)

You could try the following query:

SELECT iaw.IPAddressId, iaw.IPAddress, iaw.IPStatus, iaw.IPNumber
     , iacl.Country_Short, iacl.Country_Long, iacl.Region, iacl.City
FROM (
  SELECT IPAddressId, IPAddress, IPStatus, IPNumber,(
    SELECT MAX(IP_Address_From)
    FROM IP_Address_City_Lkp
    WHERE IP_Address_From < iaw2.IPNumber
  ) AS IP_From
  FROM StagingDatabase.dbo.IP_Addr_Work AS iaw2
) AS iaw
LEFT JOIN IP_Address_City_Lkp AS iacl
  ON  iacl.IP_Address_From = iaw.IP_From
  AND iacl.IP_Address_To   > iaw.IPNumber

The inner query looksup the correct row from IP_Address_City_Lkp, or an
incorrect row (one with an IP_Address_To < IPNumber).

The left join in the outer query fetches the corresponding
IP_Address_City_Lkp row or filters it out when it is out of range.

By the way: you omitted the keys, constraints and indexes. The query
above assumes that table IP_Address_City_Lkp has a clustered primary key
on (IP_Address_From,IP_Address_To).

Hope this helps,
Gert-Jan



Kathy wrote:
Show quote
>
> Hi Guys
>
> Thanks for the input.
> If you can give me a more efficient way of doing this as well I would really
> appreciate it
>
> ok here is the scenario
>
> We have a lookup table with IP addresses and Countries
> These IP addresses are converted to an IP number and they exist in a range
> i.e. IP_TO 680000        IP_From 680100
>
> We have a table with a list of our users IPs
> We convert the IP addresses in the users tables to a number
>
> Then we have to join the user table to the Lookup table to map the IP's to
> the countries because we need a list of all IP's with their countries
>
> The join I have is the only join I need to make but because it is a range
> one has to use between which may not be the best way to do this
> Keep in mind however that the list of user IP's is 11 million plus so the
> table is huge and we really need an effcient way to do this whether it is
> via an index or something else
>
> Here are the DDL's
>
> CREATE TABLE [IP_Addr_Work] (
>  [IPAddressId] [int] NOT NULL ,
>  [IPNumber] [bigint] NULL ,
>  [IPAddress] [char] (20) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
>  [IPStatus] [int] NULL
> ) ON [PRIMARY]
>
> CREATE TABLE [IP_Address_City_Lkp] (
>  [IP_Address_From] [bigint] NOT NULL ,
>  [IP_Address_To] [bigint] NOT NULL ,
>  [Country_Short] [char] (2) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
>  [Country_Long] [varchar] (64) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
>  [Region] [varchar] (128) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
>  [City] [varchar] (128) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
> ) ON [PRIMARY]
>
> This is the join I need to do
>
> SELECT iaw.IPAddressId, iaw.IPAddress, iaw.IPStatus
>   , IPNumber , iacl.Country_Short, iacl.Country_Long, iacl.Region, iacl.City
> FROM StagingDatabase.dbo.IP_Addr_Work AS iaw
> LEFT JOIN dbo.IP_Address_City_Lkp AS iacl
>   ON IPNumber BETWEEN iacl.IP_Address_From AND iacl.IP_Address_To
>
> "Kathy" <r**@roo.com> wrote in message
> news:VsudnXBMv5fwklnfRVn-rw@is.co.za...
> > Hi All again
> >
> > I have a question on an index
> >
> > The query is as follows
> >
> > SELECT  *
> > FROM dbo.IP_Addr_Work AS iaw LEFT JOIN dbo.IP_Address_City_Lkp AS iacl
> >  ON iaw.IPAddress BETWEEN iacl.IP_Address_From AND iacl.IP_Address_To
> >
> > What index is more efficient
> >
> > CLUSTERED INDEX ON IP_Address_From
> > and
> > CLUSTERED INDEX ON IP_Address_To
> >
> > OR
> >
> > CLUSTERED INDEX ON ( IP_Address_From , IP_Address_To)
> >
> > Your help would be much appreciated
> >
> > Thanks
> > Kathryn
> >

AddThis Social Bookmark Button