最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

在SQL SERVER中導(dǎo)致索引查找變成索引掃描的問(wèn)題分析

 更新時(shí)間:2015年09月16日 11:04:57   作者:瀟湘隱者  
SQL Server 中什么情況會(huì)導(dǎo)致其執(zhí)行計(jì)劃從索引查找(Index Seek)變成索引掃描(Index Scan)呢? 下面從幾個(gè)方面結(jié)合上下文具體場(chǎng)景做了下測(cè)試、總結(jié)、歸納。需要的朋友可以參考下本文

SQL Server 中什么情況會(huì)導(dǎo)致其執(zhí)行計(jì)劃從索引查找(Index Seek)變成索引掃描(Index Scan)呢? 下面從幾個(gè)方面結(jié)合上下文具體場(chǎng)景做了下測(cè)試、總結(jié)、歸納。

1:隱式轉(zhuǎn)換會(huì)導(dǎo)致執(zhí)行計(jì)劃從索引查找(Index Seek)變?yōu)樗饕龗呙瑁↖ndex Scan)

Implicit Conversion will cause index scan instead of index seek. While implicit conversions occur in SQL Server to allow data evaluations against different data types, they can introduce performance problems for specific data type conversions that result in an index scan occurring during the execution.  Good design practices and code reviews can easily prevent implicit conversion issues from ever occurring in your design or workload. 

如下示例,AdventureWorks2014數(shù)據(jù)庫(kù)的HumanResources.Employee表,由于NationalIDNumber字段類(lèi)型為NVARCHAR,下面SQL發(fā)生了隱式轉(zhuǎn)換,導(dǎo)致其走索引掃描(Index Scan)

SELECT NationalIDNumber, LoginID 
FROM HumanResources.Employee 
WHERE NationalIDNumber = 112457891 

clipboard

我們可以通過(guò)兩種方式避免SQL做隱式轉(zhuǎn)換:

    1:確保比較的兩者具有相同的數(shù)據(jù)類(lèi)型。

    2:使用強(qiáng)制轉(zhuǎn)換(explicit conversion)方式。

我們通過(guò)確保比較的兩者數(shù)據(jù)類(lèi)型相同后,就可以讓SQL走索引查找(Index Seek),如下所示

SELECT nationalidnumber,
    loginid
FROM  humanresources.employee
WHERE nationalidnumber = N'112457891' 

clipboard[1]

注意:并不是所有的隱式轉(zhuǎn)換都會(huì)導(dǎo)致索引查找(Index Seek)變成索引掃描(Index Scan),Implicit Conversions that cause Index Scans 博客里面介紹了那些數(shù)據(jù)類(lèi)型之間的隱式轉(zhuǎn)換才會(huì)導(dǎo)致索引掃描(Index Scan)。如下圖所示,在此不做過(guò)多介紹。

clipboard[2]

clipboard[3]

避免隱式轉(zhuǎn)換的一些措施與方法

    1:良好的設(shè)計(jì)和代碼規(guī)范(前期)

    2:對(duì)發(fā)布腳本進(jìn)行Rreview(中期)

    3:通過(guò)腳本查詢(xún)隱式轉(zhuǎn)換的SQL(后期)

下面是在數(shù)據(jù)庫(kù)從執(zhí)行計(jì)劃中搜索隱式轉(zhuǎn)換的SQL語(yǔ)句

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
DECLARE @dbname SYSNAME 
SET @dbname = QUOTENAME(DB_NAME());
WITH XMLNAMESPACES 
  (DEFAULT 'http://schemas.microsoft.com/sqlserver/2004/07/showplan') 
SELECT 
  stmt.value('(@StatementText)[1]', 'varchar(max)'), 
  t.value('(ScalarOperator/Identifier/ColumnReference/@Schema)[1]', 'varchar(128)'), 
  t.value('(ScalarOperator/Identifier/ColumnReference/@Table)[1]', 'varchar(128)'), 
  t.value('(ScalarOperator/Identifier/ColumnReference/@Column)[1]', 'varchar(128)'), 
  ic.DATA_TYPE AS ConvertFrom, 
  ic.CHARACTER_MAXIMUM_LENGTH AS ConvertFromLength, 
  t.value('(@DataType)[1]', 'varchar(128)') AS ConvertTo, 
  t.value('(@Length)[1]', 'int') AS ConvertToLength, 
  query_plan 
FROM sys.dm_exec_cached_plans AS cp 
CROSS APPLY sys.dm_exec_query_plan(plan_handle) AS qp 
CROSS APPLY query_plan.nodes('/ShowPlanXML/BatchSequence/Batch/Statements/StmtSimple') AS batch(stmt) 
CROSS APPLY stmt.nodes('.//Convert[@Implicit="1"]') AS n(t) 
JOIN INFORMATION_SCHEMA.COLUMNS AS ic 
  ON QUOTENAME(ic.TABLE_SCHEMA) = t.value('(ScalarOperator/Identifier/ColumnReference/@Schema)[1]', 'varchar(128)') 
  AND QUOTENAME(ic.TABLE_NAME) = t.value('(ScalarOperator/Identifier/ColumnReference/@Table)[1]', 'varchar(128)') 
  AND ic.COLUMN_NAME = t.value('(ScalarOperator/Identifier/ColumnReference/@Column)[1]', 'varchar(128)') 
WHERE t.exist('ScalarOperator/Identifier/ColumnReference[@Database=sql:variable("@dbname")][@Schema!="[sys]"]') = 1

2:非SARG謂詞會(huì)導(dǎo)致執(zhí)行計(jì)劃從索引查找(Index Seek)變?yōu)樗饕龗呙瑁↖ndex Scan)

    SARG(Searchable Arguments)又叫查詢(xún)參數(shù), 它的定義:用于限制搜索的一個(gè)操作,因?yàn)樗ǔJ侵敢粋€(gè)特定的匹配,一個(gè)值的范圍內(nèi)的匹配或者兩個(gè)以上條件的AND連接。不滿(mǎn)足SARG形式的語(yǔ)句最典型的情況就是包括非操作符的語(yǔ)句,如:NOT、!=、<>;、!<;、!>;NOT EXISTS、NOT IN、NOT LIKE等,另外還有像在謂詞使用函數(shù)、謂詞進(jìn)行運(yùn)算等。

2.1:索引字段使用函數(shù)會(huì)導(dǎo)致索引掃描(Index Scan)

SELECT nationalidnumber,
    loginid
FROM  humanresources.employee
WHERE SUBSTRING(nationalidnumber,1,3) = '112'

clipboard[4]

2.2索引字段進(jìn)行運(yùn)算會(huì)導(dǎo)致索引掃描(Index Scan)

    對(duì)索引字段字段進(jìn)行運(yùn)算會(huì)導(dǎo)致執(zhí)行計(jì)劃從索引查找(Index Seek)變成索引掃描(Index Scan):

SELECT * FROM Person.Person WHERE BusinessEntityID + 10 < 260

clipboard[5]

一般要盡量避免這種情況出現(xiàn),如果可以的話,盡量對(duì)SQL進(jìn)行邏輯轉(zhuǎn)換(如下所示)。雖然這個(gè)例子看起來(lái)很簡(jiǎn)單,但是在實(shí)際中,還是見(jiàn)過(guò)許多這樣的案例,就像很多人知道抽煙有害健康,但是就是戒不掉!很多人可能了解這個(gè),但是在實(shí)際操作中還是一直會(huì)犯這個(gè)錯(cuò)誤。道理就是如此!

SELECT * FROM Person.Person WHERE BusinessEntityID < 250

clipboard[6]

2.3 LIKE模糊查詢(xún)回導(dǎo)致索引掃描(Index Scan)

    Like語(yǔ)句是否屬于SARG取決于所使用的通配符的類(lèi)型, LIKE 'Condition%' 就屬于SARG、LIKE '%Condition'就屬于非SARG謂詞操作

SELECT * FROM Person.Person WHERE LastName LIKE 'Ma%'

clipboard[7]

SELECT * FROM Person.Person WHERE LastName LIKE '%Ma%'

clipboard[8]

3:SQL查詢(xún)返回?cái)?shù)據(jù)頁(yè)(Pages)達(dá)到了臨界點(diǎn)(Tipping Point)會(huì)導(dǎo)致索引掃描(Index Scan)或表掃描(Table Scan)

What is the tipping point?
It's the point where the number of rows returned is "no longer selective enough". SQL Server chooses NOT to use the nonclustered index to look up the corresponding data rows and instead performs a table scan.

    關(guān)于臨界點(diǎn)(Tipping Point),我們下面先不糾結(jié)概念了,先從一個(gè)鮮活的例子開(kāi)始吧:

SET NOCOUNT ON;
DROP TABLE TEST
CREATE TABLE TEST (OBJECT_ID INT, NAME VARCHAR(8));
CREATE INDEX PK_TEST ON TEST(OBJECT_ID)
DECLARE @Index INT =1;
WHILE @Index <= 10000
BEGIN
  INSERT INTO TEST
  SELECT @Index, 'kerry';
  SET @Index = @Index +1;
END
UPDATE STATISTICS TEST WITH FULLSCAN;
SELECT * FROM TEST WHERE OBJECT_ID= 1

如上所示,當(dāng)我們查詢(xún)OBJECT_ID=1的數(shù)據(jù)時(shí),優(yōu)化器使用索引查找(Index Seek)

clipboard[9]

上面OBJECT_ID=1的數(shù)據(jù)只有一條,如果OBJECT_ID=1的數(shù)據(jù)達(dá)到全表總數(shù)據(jù)量的20%會(huì)怎么樣? 我們可以手工更新2001條數(shù)據(jù)。此時(shí)SQL的執(zhí)行計(jì)劃變成全表掃描(Table Scan)了。

UPDATE TEST SET OBJECT_ID =1 WHERE OBJECT_ID<=2000;
UPDATE STATISTICS TEST WITH FULLSCAN;
SELECT * FROM TEST WHERE OBJECT_ID= 1

clipboard[10]

clipboard[11]

臨界點(diǎn)決定了SQL Server是使用書(shū)簽查找還是全表/索引掃描。這也意味著臨界點(diǎn)只與非覆蓋、非聚集索引有關(guān)(重點(diǎn))。

Why is the tipping point interesting?
It shows that narrow (non-covering) nonclustered indexes have fewer uses than often expected (just because a query has a column in the WHERE clause doesn't mean that SQL Server's going to use that index)
It happens at a point that's typically MUCH earlier than expected… and, in fact, sometimes this is a VERY bad thing!
Only nonclustered indexes that do not cover a query have a tipping point. Covering indexes don't have this same issue (which further proves why they're so important for performance tuning)
You might find larger tables/queries performing table scans when in fact, it might be better to use a nonclustered index. How do you know, how do you test, how do you hint and/or force… and, is that a good thing?

4:統(tǒng)計(jì)信息缺失或不正確會(huì)導(dǎo)致索引掃描(Index Scan)

     統(tǒng)計(jì)信息缺失或不正確,很容易導(dǎo)致索引查找(Index Seek)變成索引掃描(Index Scan)。 這個(gè)倒是很容易理解,但是構(gòu)造這樣的案例比較難,一時(shí)沒(méi)有想到,在此略過(guò)。

5:謂詞不是聯(lián)合索引的第一列會(huì)導(dǎo)致索引掃描(Index Scan)

SELECT * INTO Sales.SalesOrderDetail_Tmp FROM Sales.SalesOrderDetail;
CREATE INDEX PK_SalesOrderDetail_Tmp ON Sales.SalesOrderDetail_Tmp(SalesOrderID, SalesOrderDetailID);
UPDATE STATISTICS  Sales.SalesOrderDetail_Tmp WITH FULLSCAN;

下面這個(gè)SQL語(yǔ)句得到的結(jié)果是一致的,但是第二個(gè)SQL語(yǔ)句由于謂詞不是聯(lián)合索引第一列,導(dǎo)致索引掃描

SELECT * FROM Sales.SalesOrderDetail_Tmp
WHERE SalesOrderID=43659 AND SalesOrderDetailID<10

clipboard[12]

SELECT * FROM Sales.SalesOrderDetail_Tmp WHERE SalesOrderDetailID<10

clipboard[13]

相關(guān)文章

  • SQL Server 使用 Pivot 和 UnPivot 實(shí)現(xiàn)行列轉(zhuǎn)換的問(wèn)題小結(jié)

    SQL Server 使用 Pivot 和 UnPivot 

    對(duì)于行列轉(zhuǎn)換的數(shù)據(jù),通常也就是在做報(bào)表的時(shí)候用的比較多,今天就通過(guò)本文給大家總結(jié)下SQL Server 使用 Pivot 和 UnPivot 實(shí)現(xiàn)行列轉(zhuǎn)換的問(wèn)題小結(jié),感興趣的朋友一起看看吧
    2022-01-01
  • 模糊查詢(xún)的通用存儲(chǔ)過(guò)程

    模糊查詢(xún)的通用存儲(chǔ)過(guò)程

    模糊查詢(xún)的通用存儲(chǔ)過(guò)程實(shí)現(xiàn)語(yǔ)句。
    2009-07-07
  • mybatis-plus的sql語(yǔ)句打印問(wèn)題小結(jié)

    mybatis-plus的sql語(yǔ)句打印問(wèn)題小結(jié)

    這篇文章主要介紹了mybatis-plus的sql語(yǔ)句打印問(wèn)題,今天將常用的方式拷貝過(guò)來(lái)之后,發(fā)現(xiàn)沒(méi)有發(fā)生效果(開(kāi)始的時(shí)候以為是使用配置中心nacos導(dǎo)致問(wèn)題,最后經(jīng)過(guò)仔細(xì)的檢查發(fā)現(xiàn)是單詞拼錯(cuò)了),所以在這里記錄一下
    2022-04-04
  • sql server 性能優(yōu)化之nolock

    sql server 性能優(yōu)化之nolock

    在SQL Server數(shù)據(jù)庫(kù)查詢(xún)時(shí),為了提高查詢(xún)的性能,我們往往會(huì)在表后面加一個(gè)nolock,或者是with(nolock),讓數(shù)據(jù)庫(kù)在查詢(xún)時(shí)不鎖定表,從而提高查詢(xún)的速度,接下來(lái),通過(guò)本篇文章給大家詳解sql server 性能優(yōu)化之nolock,需要的朋友快來(lái)學(xué)習(xí)吧。
    2015-08-08
  • sql函數(shù)實(shí)現(xiàn)去除字符串中的相同的字符串

    sql函數(shù)實(shí)現(xiàn)去除字符串中的相同的字符串

    去除字符串中的相同的字符,此功能在開(kāi)發(fā)過(guò)程中很實(shí)用,為此本文整理了一些,希望對(duì)你了解它有所幫助
    2013-01-01
  • SQL Server清除事務(wù)日志的兩種方式

    SQL Server清除事務(wù)日志的兩種方式

    事務(wù)日志是一種記錄每次數(shù)據(jù)庫(kù)修改操作的日志,它記錄了每一次事務(wù)修改的詳細(xì)日志,但磁盤(pán)容量始終有限制,本文主要介紹了SQL Server清除事務(wù)日志的兩種方式,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-10-10
  • 新手SqlServer數(shù)據(jù)庫(kù)dba需要注意的一些小細(xì)節(jié)

    新手SqlServer數(shù)據(jù)庫(kù)dba需要注意的一些小細(xì)節(jié)

    這篇文章主要介紹了新手SqlServer數(shù)據(jù)庫(kù)dba需要注意的一些小細(xì)節(jié),本文講解了15個(gè)小細(xì)節(jié)、小技巧及需要注意的地方,需要的朋友可以參考下
    2015-02-02
  • SQL LOADER錯(cuò)誤小結(jié)

    SQL LOADER錯(cuò)誤小結(jié)

    在使用SQL*LOADER裝載數(shù)據(jù)時(shí),由于平面文件的多樣化和數(shù)據(jù)格式問(wèn)題總會(huì)遇到形形色色的一些小問(wèn)題,下面是小編抽時(shí)間整理的一些錯(cuò)誤,感興趣的朋友一起學(xué)習(xí)吧
    2015-12-12
  • SqlServer 巧妙解決多條件組合查詢(xún)

    SqlServer 巧妙解決多條件組合查詢(xún)

    開(kāi)發(fā)中經(jīng)常會(huì)遇得到需要多種條件組合查詢(xún)的情況,比如有三個(gè)表,年級(jí)表Grade(GradeId,GradeName),班級(jí)Class(ClassId,ClassName,GradeId),學(xué)員表Student(StuId,StuName,ClassId),現(xiàn)要求可以按年級(jí)Id、班級(jí)Id、學(xué)生名,這三個(gè)條件可以任意組合查詢(xún)學(xué)員信息
    2012-11-11
  • SQL Server常用存儲(chǔ)過(guò)程及示例

    SQL Server常用存儲(chǔ)過(guò)程及示例

    以下是對(duì)SQL Server中常用的存儲(chǔ)過(guò)程進(jìn)行了介紹。需要的朋友可以過(guò)來(lái)參考下
    2013-08-08

最新評(píng)論

石泉县| 勐海县| 长宁县| 静安区| 彭山县| 新郑市| 英山县| 黎川县| 明光市| 苏尼特左旗| 龙陵县| 微山县| 嘉峪关市| 南充市| 铁岭市| 综艺| 屯昌县| 介休市| 桂林市| 扶风县| 海林市| 吉首市| 岳池县| 栖霞市| 江门市| 若羌县| 焉耆| 昌邑市| 万安县| 内乡县| 万源市| 喀喇沁旗| 宜阳县| 濉溪县| 鸡泽县| 林西县| 阿克陶县| 正宁县| 阿图什市| 开封市| 芦山县|