Sql-Server
在具有許多非常相似的起始值的 VARCHAR 列上建立索引是否性能不佳
在使用索引的查詢上,我們似乎有非常不尋常的糟糕表現。例如表格看起來像
- PK BIGINT
- ID VARCHAR(50)
- Col1
- Col2
- 等等
所以我們需要在數據庫中插入一行,然後在ID上查找。但是第三方的ID,我們有PK。我們需要找回PK。但是這些 ID 中有很大一部分具有非常相似的起始值。例如
- “//45-423484834893457”
- “//45-573459834589345”
- “//45-345345345345345
我不確定 SQL Server 是如何遍歷 BTree 的,如果它對值進行雜湊處理或從最左邊的位置開始進行字元串比較。
在查詢這些值時,具有非常大範圍的非常相似的值(至少前 4 個字元是相同的)是否會導致索引性能不佳?
更新:
抱歉,查找查詢是
SELECT PK_Column FROM table WHERE ID = @ID
標記要求:
SQL Server parse and compile time: CPU time = 0 ms, elapsed time = 0 ms. SQL Server Execution Times: CPU time = 0 ms, elapsed time = 0 ms. SQL Server parse and compile time: CPU time = 0 ms, elapsed time = 22 ms. SQL Server parse and compile time: CPU time = 0 ms, elapsed time = 30 ms. (1 row(s) affected) SQL Server parse and compile time: CPU time = 0 ms, elapsed time = 0 ms. (1 row(s) affected) SQL Server parse and compile time: CPU time = 0 ms, elapsed time = 0 ms. <ShowPlanXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Version="1.1" Build="10.0.4000.0" xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan"> <BatchSequence> <Batch> <Statements> <StmtSimple StatementCompId="1" StatementEstRows="1" StatementId="1" StatementOptmLevel="TRIVIAL" StatementSubTreeCost="0.0032831" StatementText="SELECT
 LocalMsgId
 FROM
 Pdu (nolock)
 WHERE
 RemoteMsgId = '41/00/2789aeb8/1127796335811'
 
" StatementType="SELECT" ParameterizedText="(@1 varchar(8000))SELECT [LocalMsgId] FROM [Pdu](nolock) WHERE [RemoteMsgId]=@1" QueryHash="0x677C78E75E33C4C7" QueryPlanHash="0xB358D862A43E4853"> <StatementSetOptions ANSI_NULLS="true" ANSI_PADDING="true" ANSI_WARNINGS="true" ARITHABORT="true" CONCAT_NULL_YIELDS_NULL="true" NUMERIC_ROUNDABORT="false" QUOTED_IDENTIFIER="true" /> <QueryPlan CachedPlanSize="16" CompileTime="7406" CompileCPU="1970" CompileMemory="120"> <RelOp AvgRowSize="23" EstimateCPU="0.0001581" EstimateIO="0.003125" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="1" LogicalOp="Index Seek" NodeId="0" Parallel="false" PhysicalOp="Index Seek" EstimatedTotalSubtreeCost="0.0032831" TableCardinality="5074270"> <OutputList> <ColumnReference Database="[smpp]" Schema="[dbo]" Table="[Pdu]" Column="LocalMsgId" /> </OutputList> <IndexScan Ordered="true" ScanDirection="FORWARD" ForcedIndex="false" ForceSeek="false" NoExpandHint="false"> <DefinedValues> <DefinedValue> <ColumnReference Database="[smpp]" Schema="[dbo]" Table="[Pdu]" Column="LocalMsgId" /> </DefinedValue> </DefinedValues> <Object Database="[smpp]" Schema="[dbo]" Table="[Pdu]" Index="[IX_Pdu_RemoteMsgId]" IndexKind="NonClustered" /> <SeekPredicates> <SeekPredicateNew> <SeekKeys> <Prefix ScanType="EQ"> <RangeColumns> <ColumnReference Database="[smpp]" Schema="[dbo]" Table="[Pdu]" Column="RemoteMsgId" /> </RangeColumns> <RangeExpressions> <ScalarOperator ScalarString="[@1]"> <Identifier> <ColumnReference Column="@1" /> </Identifier> </ScalarOperator> </RangeExpressions> </Prefix> </SeekKeys> </SeekPredicateNew> </SeekPredicates> </IndexScan> </RelOp> <ParameterList> <ColumnReference Column="@1" ParameterCompiledValue="'41/00/2789aeb8/1127796335811'" /> </ParameterList> </QueryPlan> </StmtSimple> </Statements> <Statements> <StmtSimple StatementCompId="2" StatementId="2" StatementText="
SET STATISTICS IO OFF
" StatementType="SET STATS" /> </Statements> </Batch> <Batch> <Statements> <StmtSimple StatementCompId="1" StatementId="1" StatementText="SET STATISTICS TIME OFF
" StatementType="SET STATS" /> </Statements> </Batch> </BatchSequence> </ShowPlanXML>
這取決於您使用的查詢。MS SQL Server 使用始終平衡的 BTree 索引,但如果您使用這樣的查詢:
select * from table where field like 'some%'
並且您的大部分記錄都符合這種情況,MS SQL Server 可以決定使用表掃描而不是索引掃描或索引查找會更便宜。
從執行計劃來看,你對那個查詢真的沒什麼可做的——它已經是最優的了。
我真正的問題是:性能問題是什麼?
如果即使是單個語句也很慢,那麼系統是否足夠繁忙以至於索引頁面會超出記憶體?最大記憶體設置是否正確配置?即使有這麼寬的索引欄位,在記憶體中遍歷索引頁仍然會比較快。
如果您只是查看 Profiler 並看到很多很多這樣的小查詢,那麼我們是否在談論某種批處理過程,它恰好
SELECT
在循環中執行單行?這是一個應用程序問題——進行單例查找而不是基於集合的操作可能會使任何系統陷入癱瘓。