内存中OLTP(Hekaton)的排序警告
內存中OLTP是關于內存中的一切。但那只是對了一半。在今天的文章里我想給你展示下,當你從內存讀取數據時,即使內存中OLTP也會引起磁盤活動。這里的問題是執行計劃里,不正確的統計信息與排序(sort)運算符的組合。
排序(sort)運算符問題
我們都知道,排序(sort)運算符需要所謂的內存授予(Memory Grant)來作它的運行。內存區域是用來進行執行計劃里到來記錄的排序。內存授予的大小是基于估計行數數量。在基數計算(Cadinality Estimation)期間查詢優化器估計執行計劃里每個運算符的預計行數。
我在今年6月寫了篇文章,展示了當估計錯誤時,排序(sort)運算符如何能溢出到TempDb。在內存中OLTP里同樣的事情會發生:當估計行數錯誤時,在執行計劃里有排序(sort)運算符,排序(sort)運算符會溢出到TempDb!我們來重現這個情形。
內存中OLTP溢出到TempDb
我們新建一個有內存中OLTP文件組配置的新數據庫。?
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下一步我創建新的內存優化表:
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列創建了1個哈希索引。因為它是個哈希索引,你也需要指定哈希表上你想擁有的哈希桶數。這里我指定了1個哈希桶,這是個非常,非常糟的做法。當你往表里插入記錄時,因為只有1個哈希桶,你會得到巨大數量的哈希沖突(hash collisions)。一般來說,在你定義你的哈希索引的列上,哈希桶數應該和你列上的唯一值個數一致。下面代碼往剛才創建的表里插入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查看哈希沖突數。從這個DMV的輸出可以看到,你有14001條記錄在這個且唯一的哈希索引的哈希桶上。現在我們來運行執行計劃里有排序(sort)運算符的SELECT語句。
1 -- The sort operator in this execution plan spills over to TempDb! 2 SELECT * FROM Table1 3 ORDER BY Column1現在當你查看執行計劃時,你會看到排序運算符已經溢出到TempDb。
這是因為哈希索引上不正確的統計信息才發生的。當你查看執行計劃里Index Scan (NonClusteredHash) 運算符屬性時,你會看到查詢優化器從我們的哈希索引上估計行數為1,實際我們返回了140001行。
?
Index Scan (NonClusteredHash)?運算符的估計總是基于哈希表里哈希桶數。查詢優化器這里做出的假設是你沒有哈希沖突(hash collisions)——這在這里是不正確的。因此對排序運算符的內存授予是根據那個不正確的估計作為標準,這就會溢出到TempDb。在我的系統里這個查詢運行了近80毫秒,對于內存中技術來說這個算很長時間了。
你如何修正這個問題?刪除你的表,在哈希索引里仔細計劃哈希桶數。歡迎來到內存中OLTP的精彩世界……?
小結
當你使用內存中OLTP的哈希索引時,你要對你的哈希所用仔細設計你的哈希桶數。當它們錯誤時,是傷及性能。我已經在1個月前,寫了篇文章描述哈希沖突(hash collisions)如何傷及內存中OLTP的性能——即使沒有溢出到TempDb!
從中我們可以看出:在哈希索引有哈希沖突的話,你用內存中OLTP的話不能期望得到驚艷的快速性能,因為它們帶來巨大的負擔且影響基數計算。
感謝關注!
參考文章:
https://www.sqlpassion.at/archive/2015/02/05/memory-oltp-hekaton-sort-warnings/
總結
以上是生活随笔為你收集整理的内存中OLTP(Hekaton)的排序警告的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: crontab脚本,定时任务相关细节
- 下一篇: .NET 4.6的RyuJIT编译器中又