全部產品
Search
文件中心

Lindorm:查詢結果不符合預期的常見原因

更新時間:Jul 06, 2024

在使用Lindorm寬表引擎的過程中,如果使用方法不當,可能會出現查詢結果與預期不符的情況。本文列舉了導致此類問題產生的幾種常見原因,請您根據原因進行排查,最佳化查詢條件。

問題描述

Lindorm寬表引擎是相容HBase的NoSQL資料引擎,其儲存模型是基於LSM-Tree實現的。在執行寫入操作時,資料會被先寫入預寫記錄檔(Write-Ahead-Log,WAL)中,再寫入資料庫。只要寫入過程中沒有出現報錯,相應的資料一定會寫入成功,即使遇到機器宕機等情況,都可以通過恢複WAL的方式恢複資料,保障資料的持久性,不會出現資料寫入後非預期不可見的情況。但是由於寬表引擎的特性比較多,例如資料版本號碼、時間戳記、TTL到期等複雜特性,如果使用不當,則可能出現寫入的資料無法覆蓋、被到期刪除等無法被查詢到或查詢不符合逾期的情況,常見原因如下:

常見原因

資料未正常寫入或查詢發起的時間在資料寫入前

在Lindorm寬表引擎中,資料寫入是即時可見的,並不會出現寫入後過一段時間才可見的情況。

Lindorm寬表經常會被應用在巨量資料鏈路中,如果寫入鏈路出現問題,則可能導致寫入延遲或無法正常寫入資料,此時進行資料查詢,該行資料還未寫入,因此會產生無法查詢到資料的情況。

如果您在使用中遇到資料寫入一段時間後才能查到的情況,建議您在查詢條件中添加相關HINT參數,指定查詢結果中返回資料寫入的時間戳記,根據該時間戳記判斷是否出現了查詢先於寫入的情況。如何返回時間戳記,請參見多版本資料管理

說明

如果寫入資料時未指定時間戳記,則返回的時間戳記代表這行資料寫入的時間。

STRING欄位中含有非正常的停止符或不可見字元

在查詢資料類型為STRING的欄位時,如果STRING欄位中包含不可見字元,則可能造成查詢結果不符合逾期的現象。假設訂單列orderID為STRING類型,由於程式bug等原因,在資料寫入時加入了不可見字元,比如訂單號1000寫成了1000(不可見字元),即1000後跟有不可見字元,那麼在使用查詢條件

where oderID="1000"時,這個包含不可見字元的欄位是查詢不到的,可以使用where orderID > "1000" limit 1來確認是否存在類似問題。

此外,Lindorm不支援STRING欄位的中間包含停止符(結尾有停止符是正常STRING欄位)。假設寫入資料為“1000\停止符\1000”,可能會造成編碼異常,導致無法被查詢到。

查詢條件中列名填寫錯誤

可能包含以下兩種情況:

  • 列名大小寫錯誤:Lindorm的列名是大小寫敏感的,因此在查詢時需注意查詢條件中的列名與實際寫入的列名大小寫是否一致。

  • 未指定列簇(column family):Lindorm寬表是支援多列簇的,如果在建表時未指定family,則寫入的列預設被添加至名為f的family下,在資料查詢時無需在查詢條件中指定family。但如果使用了多family功能,則必須在查詢條件中指定family,否則系統將預設查詢f這個列簇下的資料,可能導致查詢結果與逾期不符。例如,建立了一個名為meta的family,並在meta下寫入了一個列column1,則在查詢column1中的資料時,必須指定family為meta,例如where meta:column1=xxx;如果未指定family,例如where column1=xxx,系統將預設查詢f列簇下的column1,導致查詢結果與實際想要得到的結果不一致。

表屬性設定了TTL,查詢時資料已到期

寬表引擎支援通過設定表屬性TTL來指定資料到期時間,TTL的單位是秒(s)。同時,寬表引擎也支援在寫入資料時指定時間戳記,時間戳記的單位為毫秒(ms)。

如果寫入資料時未指定時間戳記,資料將在指定的TTL時間長度後到期。例如,指定TTL的值為一天(86400秒),那麼今天寫入的資料將在明天到期被清理,無法被查詢到。

如果寫入資料時指定了較早的時間戳記,並且該時間戳記與目前時間的差值大於TTL設定值,那麼可能在寫入時就被清理掉,導致資料寫入後無法被查詢到。

重要

寬表引擎中的KV版本號碼等同於時間戳記。如果您在時間戳記的使用上未遵循時間語義,而是使用自訂的版本號碼(例如1、2、3、4這種比較小的數字),那麼在表屬性設定了TTL的情況下,資料極易被到期清理。同理,使用較大的自訂時間戳記/版本號碼,例如誤將KV的時間戳記設定成微秒時間戳記或者納秒時間戳記,則可能造成資料無法被正常到期清理。

您可以通過叢集管理系統查看TTL的值是否合適,具體步驟:在叢集管理系統的概覽頁面,單擊目標資料庫下的目標表名。在當前詳情表格地區,單擊查看錶屬性,查看TTL參數的值。如何進入叢集管理系統,請參見登入叢集管理系統

如果您需要修改TTL屬性的值,可以通過以下方式:

設定了Cell TTL,查詢時資料已到期

寬表引擎支援在某個索引值對(Key-Value,KV)上設定TTL屬性,用於控制每個KV的到期時間,即Cell TLL,單位為毫秒(ms)。

如果KV上設定了Cell TTL,則其到期時間為min{Cell上設定的到期時間,表屬性上的到期時間}。到期時間的判斷是根據KV的時間戳記或版本號碼來計算的,如果KV的時間戳記過大或過小,都有可能造成資料提早被清理或一直無法被清理,導致查詢結果不符合預期。

如果同一列中存在帶有Cell TTL的KV1和沒有帶Cell TTL的KV2,在資料到期前,查詢資料時可能會讀取到時間戳記已更新的KV1。在資料到期後,KV1將被清理,此時查詢資料可能會讀取到KV2,導致查詢結果不符合預期。

說明

是否能讀到KV2,取決於設定的表屬性VERSIONS,同時還取決於到KV1和KV2是否在不同的檔案中、KV1和KV2有沒有被Major Compaction操作合并。例如表的VERSIONS設定為1,檔案合并發生後,由於只保留一個版本,KV2會在Major Compaction操作中被刪除,因此即使KV1被到期清理,查詢資料時也無法讀取到KV2。

刪除請求的時間戳記設定不合理

Lindorm寬表引擎支援為刪除請求設定時間戳記/版本號碼,代表刪除該行/該列在此時間/版本之前的資料,如果未設定時間戳記/版本號碼,預設刪除目前時間/目前的版本之前的資料。假設未設定時間戳記,目前時間為2024年1月16日16:00:00,此時執行DELETE FROM sensor WHERE p1 = 10;表示刪除寫入時間在2024年1月16日16:00:00之前,且p1為10的一行資料。

如果刪除請求的時間戳記比資料寫入的時間戳記/版本號碼小,那麼這行資料不會被刪除,此時查詢結果中依舊會包含這行資料。

如果刪除請求設定的時間戳記/版本號碼較大,刪除請求提交後將持續生效,此時再寫入資料,則資料寫入的時間戳記比刪除請求設定的時間戳記小,資料寫入後會被立刻刪除,導致無法被查詢到。

說明

SQL訪問方式不支援設定刪除時間戳記。

鏈路等問題導致資料寫入後立刻被刪除

在一些巨量資料鏈路中,如果寫入和刪除發生在的不同的程式或進程中,則可能會出現資料寫入後被立刻刪除的情況,需要進行排查。

此外,如果您是使用阿里雲Realtime ComputeFlink並採用Flink SQL方式訪問Lindorm寬表,需注意舊版本的Flink Lindorm Connector可能產生的問題:在更新Lindorm表時,如果一條Delete操作和資料寫入的時間非常接近,可能會導致寫入操作被Delete操作覆蓋。您可以通過在Flink中設定ignoreDelete=true來規避該問題。

更多介紹,請參見Flink的Lindorm Conenctor

表屬性VERSIONS被設定為0導致資料被刪除

寬表的VERSIONS屬性的值為0,表示表中的資料不會保留,任何寫入的資料都將被刪除,無法查詢。如果建表時未設定VERSIONS屬性,則VERSIONS的值預設為1,即表中的資料僅保留一個版本。更多介紹,請參見多版本資料管理

如果誤把VERSIONS屬性的值設定為0,建議您刪除表並重建立表,或將VERSIONS屬性修改為大於等於1的值。

您可以通過叢集管理系統查看VERSIONS的值是否為0,具體步驟:在叢集管理系統的概覽頁面,單擊目標資料庫下的目標表名。在當前詳情表格地區,單擊查看錶屬性,查看VERSIONS參數的值。如何進入叢集管理系統,請參見登入叢集管理系統

如果您需要修改VERSIONS屬性的值,可以通過以下方式:

說明

MIN_VERSIONS代表保留的最少版本數,該屬性預設為0,不會造成資料寫入後無法被查到的情況。

表屬性為IMMUTABLE的表有更新

表的屬性被設定成IMMUTABLE表示該表僅支援整行寫入(即一行的資料通過一條UPSERT語句寫入,不支援一行的資料通過多條UPSERT語句寫入),不可更新或刪除。但在實際操作中,即使表的屬性被設定成IMMUTABLE,Lindorm也並不會禁止更新和刪除行為,但該類操作會造成索引表和主表的資料不一致,進而導致查詢命中索引和命中主表的結果不一致。

建議您重新構建索引表,並停止更新或刪除屬性為IMMUTABLE的表中的資料。