内存中OLTP(Hekaton)的排序警告
內(nèi)存中OLTP是關(guān)于內(nèi)存中的一切。但那只是對了一半。在今天的文章里我想給你展示下,當你從內(nèi)存讀取數(shù)據(jù)時,即使內(nèi)存中OLTP也會引起磁盤活動。這里的問題是執(zhí)行計劃里,不正確的統(tǒng)計信息與排序(sort)運算符的組合。
排序(sort)運算符問題
我們都知道,排序(sort)運算符需要所謂的內(nèi)存授予(Memory Grant)來作它的運行。內(nèi)存區(qū)域是用來進行執(zhí)行計劃里到來記錄的排序。內(nèi)存授予的大小是基于估計行數(shù)數(shù)量。在基數(shù)計算(Cadinality Estimation)期間查詢優(yōu)化器估計執(zhí)行計劃里每個運算符的預(yù)計行數(shù)。
我在今年6月寫了篇文章,展示了當估計錯誤時,排序(sort)運算符如何能溢出到TempDb。在內(nèi)存中OLTP里同樣的事情會發(fā)生:當估計行數(shù)錯誤時,在執(zhí)行計劃里有排序(sort)運算符,排序(sort)運算符會溢出到TempDb!我們來重現(xiàn)這個情形。
內(nèi)存中OLTP溢出到TempDb
我們新建一個有內(nèi)存中OLTP文件組配置的新數(shù)據(jù)庫。?
1 -- Create new database 2 CREATE DATABASE HashCollisions 3 GO 4 5 -- Add MEMORY_OPTIMIZED_DATA filegroup to the database. 6 ALTER DATABASE HashCollisions 7 ADD FILEGROUP InMemoryOLTPFileGroup CONTAINS MEMORY_OPTIMIZED_DATA 8 GO 9 10 USE HashCollisions 11 GO 12 13 -- Add a new file to the previously created file group 14 ALTER DATABASE HashCollisions ADD FILE 15 ( 16 NAME = N'InMemoryOLTPContainer', 17 FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL12.SQL2014\MSSQL\DATA\InMemoryOLTPContainer' 18 ) 19 TO FILEGROUP [InMemoryOLTPFileGroup] 20 GO下一步我創(chuàng)建新的內(nèi)存優(yōu)化表:
1 -- Create a test table 2 CREATE TABLE Table1 3 ( 4 Column1 INT IDENTITY, 5 Column2 INT 6 CONSTRAINT pk_Column1 PRIMARY KEY NONCLUSTERED HASH (Column1) WITH (BUCKET_COUNT = 1) 7 ) WITH 8 ( 9 MEMORY_OPTIMIZED = ON, 10 DURABILITY = SCHEMA_ONLY 11 ) 12 GO從表定義可以看到,我在Column1列創(chuàng)建了1個哈希索引。因為它是個哈希索引,你也需要指定哈希表上你想擁有的哈希桶數(shù)。這里我指定了1個哈希桶,這是個非常,非常糟的做法。當你往表里插入記錄時,因為只有1個哈希桶,你會得到巨大數(shù)量的哈希沖突(hash collisions)。一般來說,在你定義你的哈希索引的列上,哈希桶數(shù)應(yīng)該和你列上的唯一值個數(shù)一致。下面代碼往剛才創(chuàng)建的表里插入14001條記錄。
1 -- Insert 14001 records 2 INSERT INTO Table1(Column2) VALUES (1) 3 4 SELECT TOP 14000 IDENTITY(INT, 1, 1) AS n INTO #Nums 5 FROM 6 master.dbo.syscolumns sc1 7 8 INSERT INTO Table1 (Column2) 9 SELECT 2 FROM #nums 10 DROP TABLE #nums 11 GO你可以通過DMV?sys.dm_db_xtp_hash_index_stats查看哈希沖突數(shù)。從這個DMV的輸出可以看到,你有14001條記錄在這個且唯一的哈希索引的哈希桶上。現(xiàn)在我們來運行執(zhí)行計劃里有排序(sort)運算符的SELECT語句。
1 -- The sort operator in this execution plan spills over to TempDb! 2 SELECT * FROM Table1 3 ORDER BY Column1現(xiàn)在當你查看執(zhí)行計劃時,你會看到排序運算符已經(jīng)溢出到TempDb。
這是因為哈希索引上不正確的統(tǒng)計信息才發(fā)生的。當你查看執(zhí)行計劃里Index Scan (NonClusteredHash) 運算符屬性時,你會看到查詢優(yōu)化器從我們的哈希索引上估計行數(shù)為1,實際我們返回了140001行。
?
Index Scan (NonClusteredHash)?運算符的估計總是基于哈希表里哈希桶數(shù)。查詢優(yōu)化器這里做出的假設(shè)是你沒有哈希沖突(hash collisions)——這在這里是不正確的。因此對排序運算符的內(nèi)存授予是根據(jù)那個不正確的估計作為標準,這就會溢出到TempDb。在我的系統(tǒng)里這個查詢運行了近80毫秒,對于內(nèi)存中技術(shù)來說這個算很長時間了。
你如何修正這個問題?刪除你的表,在哈希索引里仔細計劃哈希桶數(shù)。歡迎來到內(nèi)存中OLTP的精彩世界……?
小結(jié)
當你使用內(nèi)存中OLTP的哈希索引時,你要對你的哈希所用仔細設(shè)計你的哈希桶數(shù)。當它們錯誤時,是傷及性能。我已經(jīng)在1個月前,寫了篇文章描述哈希沖突(hash collisions)如何傷及內(nèi)存中OLTP的性能——即使沒有溢出到TempDb!
從中我們可以看出:在哈希索引有哈希沖突的話,你用內(nèi)存中OLTP的話不能期望得到驚艷的快速性能,因為它們帶來巨大的負擔(dān)且影響基數(shù)計算。
感謝關(guān)注!
參考文章:
https://www.sqlpassion.at/archive/2015/02/05/memory-oltp-hekaton-sort-warnings/
總結(jié)
以上是生活随笔為你收集整理的内存中OLTP(Hekaton)的排序警告的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: crontab脚本,定时任务相关细节
- 下一篇: .NET 4.6的RyuJIT编译器中又