问题
I have a table in sql server 2005 which holds an ip range and the corresponding info (country / city / etc). There are approximately 3 million rows and it currently takes just over half a second to return a record based on the query below.
DECLARE @ip BIGINT
SELECT @ip=3561360969
SELECT TOP 1 id, ipfrom, ipto, countrycode, countryname,region,city
FROM tbl_ip
WHERE ipfrom <= @ip and @ip <= ipto
Can anyone offer any suggestions to improve the query time as the system I'm building needs to handle about 10 of these queries a second. I've already done the following which hasn't improved the query time much...
- Set the database to read only
- Used the NOLOCK table hint
- Indexed the ipfrom & ipto columns
Any ideas would be much appreciated!
Tim
Edit: The xml execution plan is below:
<ShowPlanXML xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan" Version="1.0" Build="9.00.4053.00"><BatchSequence><Batch><Statements><StmtSimple StatementText="set statistics time on

" StatementId="1" StatementCompId="1" StatementType="SET STATS"/><StmtSimple StatementText="
DECLARE @ip BIGINT
SELECT @ip=3561360969
" StatementId="2" StatementCompId="2" StatementType="ASSIGN"/><StmtSimple StatementText="
SELECT top 1 id, ipfrom, ipto, countrycode, countryname,region,city
FROM tbl_ip 
WHERE ipfrom <= @ip and @ip <= ipto

" StatementId="3" StatementCompId="3" StatementType="SELECT" StatementSubTreeCost="0.00337934" StatementEstRows="1" StatementOptmLevel="TRIVIAL"><StatementSetOptions QUOTED_IDENTIFIER="false" ARITHABORT="true" CONCAT_NULL_YIELDS_NULL="false" ANSI_NULLS="false" ANSI_PADDING="false" ANSI_WARNINGS="false" NUMERIC_ROUNDABORT="false"/><QueryPlan CachedPlanSize="8" CompileTime="0" CompileCPU="0" CompileMemory="120"><RelOp NodeId="0" PhysicalOp="Top" LogicalOp="Top" EstimateRows="1" EstimateIO="0" EstimateCPU="1e-007" AvgRowSize="393" EstimatedTotalSubtreeCost="0.00337934" Parallel="0" EstimateRebinds="0" EstimateRewinds="0"><OutputList><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Id"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPFrom"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPTo"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="CountryCode"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="CountryName"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Region"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="City"/></OutputList><Top RowCount="0" IsPercent="0" WithTies="0"><TopExpression><ScalarOperator ScalarString="(1)"><Const ConstValue="(1)"/></ScalarOperator></TopExpression><RelOp NodeId="1" PhysicalOp="Clustered Index Scan" LogicalOp="Clustered Index Scan" EstimateRows="1" EstimateIO="28.1505" EstimateCPU="3.77105" AvgRowSize="393" EstimatedTotalSubtreeCost="0.00337724" Parallel="0" EstimateRebinds="0" EstimateRewinds="0"><OutputList><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Id"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPFrom"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPTo"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="CountryCode"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="CountryName"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Region"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="City"/></OutputList><IndexScan Ordered="0" ForcedIndex="0" NoExpandHint="0"><DefinedValues><DefinedValue><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Id"/></DefinedValue><DefinedValue><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPFrom"/></DefinedValue><DefinedValue><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPTo"/></DefinedValue><DefinedValue><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="CountryCode"/></DefinedValue><DefinedValue><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="CountryName"/></DefinedValue><DefinedValue><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Region"/></DefinedValue><DefinedValue><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="City"/></DefinedValue></DefinedValues><Object Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Index="[PK_tbl_IP2]"/><Predicate><ScalarOperator ScalarString="[RecruitmentIP].[dbo].[tbl_IP].[IPFrom]<=[@ip] AND [@ip]<=[RecruitmentIP].[dbo].[tbl_IP].[IPTo]"><Logical Operation="AND"><ScalarOperator><Compare CompareOp="LE"><ScalarOperator><Identifier><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPFrom"/></Identifier></ScalarOperator><ScalarOperator><Identifier><ColumnReference Column="@ip"/></Identifier></ScalarOperator></Compare></ScalarOperator><ScalarOperator><Compare CompareOp="LE"><ScalarOperator><Identifier><ColumnReference Column="@ip"/></Identifier></ScalarOperator><ScalarOperator><Identifier><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPTo"/></Identifier></ScalarOperator></Compare></ScalarOperator></Logical></ScalarOperator></Predicate></IndexScan></RelOp></Top></RelOp></QueryPlan></StmtSimple><StmtSimple StatementText="
set statistics time off" StatementId="4" StatementCompId="4" StatementType="SET STATS"/></Statements></Batch></BatchSequence></ShowPlanXML>
Execution plan with index on ipfrom, ipto
<ShowPlanXML xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan" Version="1.0" Build="9.00.4053.00"><BatchSequence><Batch><Statements><StmtSimple StatementText="DECLARE @ip BIGINT
SELECT @ip=3561360969
" StatementId="1" StatementCompId="1" StatementType="ASSIGN"/><StmtSimple StatementText="
SELECT top 1 id, ipfrom, ipto, countrycode, countryname,region,city
FROM tbl_ip 
WHERE ipfrom <= @ip and @ip <= ipto
ORDER BY ipto
" StatementId="2" StatementCompId="2" StatementType="SELECT" StatementSubTreeCost="224.264" StatementEstRows="1" StatementOptmLevel="FULL"><StatementSetOptions QUOTED_IDENTIFIER="false" ARITHABORT="true" CONCAT_NULL_YIELDS_NULL="false" ANSI_NULLS="false" ANSI_PADDING="false" ANSI_WARNINGS="false" NUMERIC_ROUNDABORT="false"/><QueryPlan CachedPlanSize="10" CompileTime="1" CompileCPU="1" CompileMemory="160"><RelOp NodeId="0" PhysicalOp="Sort" LogicalOp="TopN Sort" EstimateRows="1" EstimateIO="182.872" EstimateCPU="6.45397" AvgRowSize="393" EstimatedTotalSubtreeCost="224.264" Parallel="0" EstimateRebinds="0" EstimateRewinds="0"><OutputList><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Id"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPFrom"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPTo"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="CountryCode"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="CountryName"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Region"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="City"/></OutputList><MemoryFractions Input="0" Output="1"/><TopSort Distinct="0" Rows="1"><OrderBy><OrderByColumn Ascending="1"><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPTo"/></OrderByColumn></OrderBy><RelOp NodeId="1" PhysicalOp="Clustered Index Scan" LogicalOp="Clustered Index Scan" EstimateRows="308528" EstimateIO="28.1505" EstimateCPU="3.77105" AvgRowSize="393" EstimatedTotalSubtreeCost="31.9216" Parallel="0" EstimateRebinds="0" EstimateRewinds="0"><OutputList><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Id"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPFrom"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPTo"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="CountryCode"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="CountryName"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Region"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="City"/></OutputList><IndexScan Ordered="0" ForcedIndex="0" NoExpandHint="0"><DefinedValues><DefinedValue><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Id"/></DefinedValue><DefinedValue><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPFrom"/></DefinedValue><DefinedValue><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPTo"/></DefinedValue><DefinedValue><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="CountryCode"/></DefinedValue><DefinedValue><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="CountryName"/></DefinedValue><DefinedValue><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Region"/></DefinedValue><DefinedValue><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="City"/></DefinedValue></DefinedValues><Object Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Index="[PK_tbl_IP2]"/><Predicate><ScalarOperator ScalarString="[RecruitmentIP].[dbo].[tbl_IP].[IPFrom]<=[@ip] AND [@ip]<=[RecruitmentIP].[dbo].[tbl_IP].[IPTo]"><Logical Operation="AND"><ScalarOperator><Compare CompareOp="LE"><ScalarOperator><Identifier><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPFrom"/></Identifier></ScalarOperator><ScalarOperator><Identifier><ColumnReference Column="@ip"/></Identifier></ScalarOperator></Compare></ScalarOperator><ScalarOperator><Compare CompareOp="LE"><ScalarOperator><Identifier><ColumnReference Column="@ip"/></Identifier></ScalarOperator><ScalarOperator><Identifier><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPTo"/></Identifier></ScalarOperator></Compare></ScalarOperator></Logical></ScalarOperator></Predicate></IndexScan></RelOp></TopSort></RelOp></QueryPlan></StmtSimple></Statements></Batch></BatchSequence></ShowPlanXML>
execution plan for Martin Smiths query:
<ShowPlanXML xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan" Version="1.0" Build="9.00.4053.00"><BatchSequence><Batch><Statements><StmtSimple StatementText="--set showplan_xml on

set statistics time on

" StatementId="1" StatementCompId="1" StatementType="SET STATS"/><StmtSimple StatementText="
DECLARE @ip BIGINT
SELECT @ip=3561360969

" StatementId="2" StatementCompId="2" StatementType="ASSIGN"/><StmtSimple StatementText="
SELECT id, ipfrom, ipto, countrycode, countryname,region,city FROM
(
SELECT TOP 1 id, ipfrom, ipto, countrycode, countryname,region,city
FROM tbl_ip 
WHERE @ip <= ipto
ORDER BY ipto
INTERSECT
SELECT TOP 1 id, ipfrom, ipto, countrycode, countryname,region,city
FROM tbl_ip 
WHERE ipfrom <= @ip
ORDER BY ipfrom DESC
) ip

" StatementId="3" StatementCompId="3" StatementType="SELECT" StatementSubTreeCost="226.409" StatementEstRows="1" StatementOptmLevel="FULL"><StatementSetOptions QUOTED_IDENTIFIER="false" ARITHABORT="true" CONCAT_NULL_YIELDS_NULL="false" ANSI_NULLS="false" ANSI_PADDING="false" ANSI_WARNINGS="false" NUMERIC_ROUNDABORT="false"/><QueryPlan CachedPlanSize="33" CompileTime="6" CompileCPU="6" CompileMemory="376"><MissingIndexes><MissingIndexGroup Impact="10.1146"><MissingIndex Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]"><ColumnGroup Usage="INEQUALITY"><Column Name="[IPTo]" ColumnId="3"/></ColumnGroup><ColumnGroup Usage="INCLUDE"><Column Name="[Id]" ColumnId="1"/><Column Name="[IPFrom]" ColumnId="2"/><Column Name="[CountryCode]" ColumnId="4"/><Column Name="[CountryName]" ColumnId="5"/><Column Name="[Region]" ColumnId="6"/><Column Name="[City]" ColumnId="7"/></ColumnGroup></MissingIndex></MissingIndexGroup></MissingIndexes><RelOp NodeId="0" PhysicalOp="Nested Loops" LogicalOp="Left Semi Join" EstimateRows="1" EstimateIO="0" EstimateCPU="4.18e-006" AvgRowSize="86" EstimatedTotalSubtreeCost="226.409" Parallel="0" EstimateRebinds="0" EstimateRewinds="0"><OutputList><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Id"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPFrom"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPTo"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="CountryCode"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="CountryName"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Region"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="City"/></OutputList><NestedLoops Optimized="0"><Predicate><ScalarOperator ScalarString="[RecruitmentIP].[dbo].[tbl_IP].[Id]=[RecruitmentIP].[dbo].[tbl_IP].[Id] AND [RecruitmentIP].[dbo].[tbl_IP].[IPFrom] = [RecruitmentIP].[dbo].[tbl_IP].[IPFrom] AND [RecruitmentIP].[dbo].[tbl_IP].[IPTo] = [RecruitmentIP].[dbo].[tbl_IP].[IPTo] AND [RecruitmentIP].[dbo].[tbl_IP].[CountryCode] = [RecruitmentIP].[dbo].[tbl_IP].[CountryCode] AND [RecruitmentIP].[dbo].[tbl_IP].[CountryName] = [RecruitmentIP].[dbo].[tbl_IP].[CountryName] AND [RecruitmentIP].[dbo].[tbl_IP].[Region] = [RecruitmentIP].[dbo].[tbl_IP].[Region] AND [RecruitmentIP].[dbo].[tbl_IP].[City] = [RecruitmentIP].[dbo].[tbl_IP].[City]"><Logical Operation="AND"><ScalarOperator><Compare CompareOp="EQ"><ScalarOperator><Identifier><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Id"/></Identifier></ScalarOperator><ScalarOperator><Identifier><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Id"/></Identifier></ScalarOperator></Compare></ScalarOperator><ScalarOperator><Compare CompareOp="IS"><ScalarOperator><Identifier><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPFrom"/></Identifier></ScalarOperator><ScalarOperator><Identifier><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPFrom"/></Identifier></ScalarOperator></Compare></ScalarOperator><ScalarOperator><Compare CompareOp="IS"><ScalarOperator><Identifier><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPTo"/></Identifier></ScalarOperator><ScalarOperator><Identifier><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPTo"/></Identifier></ScalarOperator></Compare></ScalarOperator><ScalarOperator><Compare CompareOp="IS"><ScalarOperator><Identifier><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="CountryCode"/></Identifier></ScalarOperator><ScalarOperator><Identifier><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="CountryCode"/></Identifier></ScalarOperator></Compare></ScalarOperator><ScalarOperator><Compare CompareOp="IS"><ScalarOperator><Identifier><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="CountryName"/></Identifier></ScalarOperator><ScalarOperator><Identifier><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="CountryName"/></Identifier></ScalarOperator></Compare></ScalarOperator><ScalarOperator><Compare CompareOp="IS"><ScalarOperator><Identifier><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Region"/></Identifier></ScalarOperator><ScalarOperator><Identifier><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Region"/></Identifier></ScalarOperator></Compare></ScalarOperator><ScalarOperator><Compare CompareOp="IS"><ScalarOperator><Identifier><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="City"/></Identifier></ScalarOperator><ScalarOperator><Identifier><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="City"/></Identifier></ScalarOperator></Compare></ScalarOperator></Logical></ScalarOperator></Predicate><RelOp NodeId="1" PhysicalOp="Filter" LogicalOp="Filter" EstimateRows="1" EstimateIO="0" EstimateCPU="4.8e-007" AvgRowSize="86" EstimatedTotalSubtreeCost="226.399" Parallel="0" EstimateRebinds="0" EstimateRewinds="0"><OutputList><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Id"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPFrom"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPTo"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="CountryCode"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="CountryName"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Region"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="City"/></OutputList><Filter StartupExpression="0"><RelOp NodeId="2" PhysicalOp="Sort" LogicalOp="TopN Sort" EstimateRows="1" EstimateIO="163.119" EstimateCPU="29.7123" AvgRowSize="86" EstimatedTotalSubtreeCost="226.399" Parallel="0" EstimateRebinds="0" EstimateRewinds="0"><OutputList><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Id"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPFrom"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPTo"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="CountryCode"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="CountryName"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Region"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="City"/></OutputList><MemoryFractions Input="0" Output="0"/><TopSort Distinct="0" Rows="1"><OrderBy><OrderByColumn Ascending="1"><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPTo"/></OrderByColumn></OrderBy><RelOp NodeId="3" PhysicalOp="Clustered Index Scan" LogicalOp="Clustered Index Scan" EstimateRows="1.02843e+006" EstimateIO="28.1505" EstimateCPU="3.77105" AvgRowSize="86" EstimatedTotalSubtreeCost="31.9216" Parallel="0" EstimateRebinds="0" EstimateRewinds="0"><OutputList><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Id"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPFrom"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPTo"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="CountryCode"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="CountryName"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Region"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="City"/></OutputList><IndexScan Ordered="0" ForcedIndex="0" NoExpandHint="0"><DefinedValues><DefinedValue><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Id"/></DefinedValue><DefinedValue><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPFrom"/></DefinedValue><DefinedValue><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPTo"/></DefinedValue><DefinedValue><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="CountryCode"/></DefinedValue><DefinedValue><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="CountryName"/></DefinedValue><DefinedValue><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Region"/></DefinedValue><DefinedValue><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="City"/></DefinedValue></DefinedValues><Object Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Index="[PK_tbl_IP2]" TableReferenceId="1"/><Predicate><ScalarOperator ScalarString="[@ip]<=[RecruitmentIP].[dbo].[tbl_IP].[IPTo]"><Compare CompareOp="LE"><ScalarOperator><Identifier><ColumnReference Column="@ip"/></Identifier></ScalarOperator><ScalarOperator><Identifier><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPTo"/></Identifier></ScalarOperator></Compare></ScalarOperator></Predicate></IndexScan></RelOp></TopSort></RelOp><Predicate><ScalarOperator ScalarString="[RecruitmentIP].[dbo].[tbl_IP].[IPFrom]<=[@ip]"><Compare CompareOp="LE"><ScalarOperator><Identifier><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPFrom"/></Identifier></ScalarOperator><ScalarOperator><Identifier><ColumnReference Column="@ip"/></Identifier></ScalarOperator></Compare></ScalarOperator></Predicate></Filter></RelOp><RelOp NodeId="5" PhysicalOp="Filter" LogicalOp="Filter" EstimateRows="1" EstimateIO="0" EstimateCPU="4.8e-007" AvgRowSize="86" EstimatedTotalSubtreeCost="0.00985397" Parallel="0" EstimateRebinds="0" EstimateRewinds="0"><OutputList><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Id"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPFrom"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPTo"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="CountryCode"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="CountryName"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Region"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="City"/></OutputList><Filter StartupExpression="0"><RelOp NodeId="6" PhysicalOp="Top" LogicalOp="Top" EstimateRows="1" EstimateIO="0" EstimateCPU="1e-007" AvgRowSize="86" EstimatedTotalSubtreeCost="0.00985349" Parallel="0" EstimateRebinds="0" EstimateRewinds="0"><OutputList><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Id"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPFrom"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPTo"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="CountryCode"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="CountryName"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Region"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="City"/></OutputList><Top RowCount="0" IsPercent="0" WithTies="0"><TopExpression><ScalarOperator ScalarString="(1)"><Const ConstValue="(1)"/></ScalarOperator></TopExpression><RelOp NodeId="7" PhysicalOp="Nested Loops" LogicalOp="Inner Join" EstimateRows="1" EstimateIO="0" EstimateCPU="4.29882" AvgRowSize="86" EstimatedTotalSubtreeCost="0.00985339" Parallel="0" EstimateRebinds="0" EstimateRewinds="0"><OutputList><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Id"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPFrom"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPTo"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="CountryCode"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="CountryName"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Region"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="City"/></OutputList><NestedLoops Optimized="0" WithOrderedPrefetch="1"><OuterReferences><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Id"/><ColumnReference Column="Expr1006"/></OuterReferences><RelOp NodeId="9" PhysicalOp="Index Seek" LogicalOp="Index Seek" EstimateRows="1" EstimateIO="2.45201" EstimateCPU="1.13142" AvgRowSize="27" EstimatedTotalSubtreeCost="0.0032831" Parallel="0" EstimateRebinds="0" EstimateRewinds="0"><OutputList><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Id"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPFrom"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPTo"/></OutputList><IndexScan Ordered="1" ScanDirection="BACKWARD" ForcedIndex="0" NoExpandHint="0"><DefinedValues><DefinedValue><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Id"/></DefinedValue><DefinedValue><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPFrom"/></DefinedValue><DefinedValue><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPTo"/></DefinedValue></DefinedValues><Object Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Index="[idx_ipfrom_ipto]" TableReferenceId="2"/><SeekPredicates><SeekPredicate><EndRange ScanType="LE"><RangeColumns><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPFrom"/></RangeColumns><RangeExpressions><ScalarOperator ScalarString="[@ip]"><Identifier><ColumnReference Column="@ip"/></Identifier></ScalarOperator></RangeExpressions></EndRange></SeekPredicate></SeekPredicates></IndexScan></RelOp><RelOp NodeId="11" PhysicalOp="Clustered Index Seek" LogicalOp="Clustered Index Seek" EstimateRows="1" EstimateIO="0.003125" EstimateCPU="0.0001581" AvgRowSize="373" EstimatedTotalSubtreeCost="0.00669221" Parallel="0" EstimateRebinds="1" EstimateRewinds="0.797604"><OutputList><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="CountryCode"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="CountryName"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Region"/><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="City"/></OutputList><IndexScan Lookup="1" Ordered="1" ScanDirection="FORWARD" ForcedIndex="0" NoExpandHint="0"><DefinedValues><DefinedValue><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="CountryCode"/></DefinedValue><DefinedValue><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="CountryName"/></DefinedValue><DefinedValue><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Region"/></DefinedValue><DefinedValue><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="City"/></DefinedValue></DefinedValues><Object Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Index="[PK_tbl_IP2]" TableReferenceId="-1"/><SeekPredicates><SeekPredicate><Prefix ScanType="EQ"><RangeColumns><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Id"/></RangeColumns><RangeExpressions><ScalarOperator ScalarString="[RecruitmentIP].[dbo].[tbl_IP].[Id]"><Identifier><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="Id"/></Identifier></ScalarOperator></RangeExpressions></Prefix></SeekPredicate></SeekPredicates></IndexScan></RelOp></NestedLoops></RelOp></Top></RelOp><Predicate><ScalarOperator ScalarString="[RecruitmentIP].[dbo].[tbl_IP].[IPTo]>=[@ip]"><Compare CompareOp="GE"><ScalarOperator><Identifier><ColumnReference Database="[RecruitmentIP]" Schema="[dbo]" Table="[tbl_IP]" Column="IPTo"/></Identifier></ScalarOperator><ScalarOperator><Identifier><ColumnReference Column="@ip"/></Identifier></ScalarOperator></Compare></ScalarOperator></Predicate></Filter></RelOp></NestedLoops></RelOp></QueryPlan></StmtSimple><StmtSimple StatementText="
set statistics time off" StatementId="4" StatementCompId="4" StatementType="SET STATS"/></Statements></Batch></BatchSequence></ShowPlanXML>
回答1:
How does this perform? I'm hoping that it should use an index seek on ipto to quickly resolve the top part, an index seek on ipfrom to resolve the bottom part and 2 (or possibly one) bookmark lookups to get the rest of the columns to return.
SELECT id, ipfrom, ipto, countrycode, countryname,region,city FROM
(
SELECT TOP 1 id, ipfrom, ipto, countrycode, countryname,region,city
FROM tbl_ip
WHERE @ip <= ipto
ORDER BY ipto
INTERSECT
SELECT TOP 1 id, ipfrom, ipto, countrycode, countryname,region,city
FROM tbl_ip
WHERE ipfrom <= @ip
ORDER BY ipfrom DESC
) ip
回答2:
I think the main reason why the query is slow even with index ipfrom, ipto is that the engine can not use the index properly.
It takes the first condition ipfrom <= @ip
and is able to use index for that, however this inequality has a low selection and if your ip ranges cover all ips and are not overlapping then for the index has only one ipto entry for each ipfrom index leaf.
That is not so useful and it ends up doing full index scan (assumption1).
So, to speed it up there are several tricks
1) If select @ip_max_delta = max(ipto-ipfrom)
is not to big (~1000 records) you can add WHERE ipfrom > (@ip - @ip_max_delta)
(this is directly usable only if ip's are stored as int). This will work well with any index starting with ipfrom
2)
SELECT TOP 1 id, ipfrom, ipto, countrycode, countryname,region,city
FROM tbl_ip
WHERE ipfrom <= @ip
ORDER BY ipfrom DESC
This should return really quickly (especially if you cluster on ipfrom and you should as your data rarely changes).
If the above does not return quickly can you test the execution time (and plan) on the following query, just for reference
SELECT id, ipfrom, ipto, countrycode, countryname,region,city
FROM tbl_ip
WHERE ipfrom = @ip
(choose existing @ip that exists in ipfrom column)
EDIT2: Re Martin's solution
I don't see reason to a) use intersection/subquery and b) to maintain two indexes
SELECT TOP 1 id, ipfrom, ipto, countrycode, countryname,region,city
FROM tbl_ip
WHERE ipfrom <= @ip
ORDER BY ipfrom DESC
Should return the same as Martin's query if there is correlation between ipfrom and ipto in consecutive rows. If not then additional condition can be applied directly
SELECT TOP 1 id, ipfrom, ipto, countrycode, countryname,region,city
FROM tbl_ip
WHERE ipfrom <= @ip AND @ip <= ipto
ORDER BY ipfrom DESC
This query is quite similar to the starting one, but the ORDER BY should allow parser to choose better plan (unverfied). If it does not then
SELECT id, ipfrom, ipto, countrycode, countryname,region,city
FROM
(SELECT TOP 1 id, ipfrom, ipto, countrycode, countryname,region,city
FROM tbl_ip
WHERE ipfrom <= @ip
ORDER BY ipfrom DESC) s
WHERE @ip <= ipto
Should do the trick and would require only index on ipfrom.
回答3:
Try adding this to the WHERE clause AND ipfrom <= ipto
回答4:
Is your clustered index on id? If so, you could maybe change it to ipfrom, ipto.
回答5:
What are your indexes? Would it help if you had one covering index? So ipfrom, ipto on one index? Could then even "include" id, countrycode, countryname, region, and city fields in that index so system does not have to go to data pages to get that data.
-Krip
回答6:
I see two ways to reduce execution time
1.Simple one would be to Cache whole 3m of records and use .NET native Datasets to retrieve wanted item in IP range. This will obviously eat your server CPU but you won't make 10 calls to DB every second.
2.Harder one would be to split IPs to different tables like IPRanges1 .... IPRanges9. So once you get user IP and want to query other details, you just pass to query another param with first digit of IP. This will reduce looping through 3M to 3m/9 (or something like that). Reduce in execution time will be obvious. If you combine it with Caching method you will end up with something proper.
回答7:
If ip ranges start at powers of 2 (and they should), you could exploit the fact that ip = ipfrom or ip = ipfrom & 11...10 or ip = ipfrom & 11...00, etc...
32 index lookups should be faster than a index range scan.
Just a thought.
回答8:
there is a more simple and logical solution:
1) create an extra column in your ip_country table: Arange which is actually ip_from / 16777216
2) create a clustered index on Arange, ip_from
3) use "[ipaddress]/16777216 =Arange and [ipaddress] between ip_from and ip_to" in your query
回答9:
if you are sure that the resulting data is just one row, then you can use ForceSeek option
回答10:
May be review possibility to change architecture? (Using MSSQL hints me that you can use .Net) Since you use readonly database review some: in memory database. Or try OracleCoherence for .Net (http://coherence.oracle.com/)
回答11:
You probably need to separate out the data into two tables: IPData (ipfrom, ipto, locationid) and LocationData (locationid, countryname, city, etc)
I would change the where clause to:
WHERE @ip BETWEEN ipfrom AND ipto
来源:https://stackoverflow.com/questions/3179053/improving-query-times-a-sql-ip-lookup-database