Mysql

我可以有效地將 spamassassin 貝氏令牌從 utf8 CHAR(5) 轉換為 BINARY(5) 嗎?

  • August 7, 2020

我的 spamassassin 設置非常舊,並且已經遷移到兩台機器和多個 mysql 重新安裝。我最近注意到,sa-learn在消息上執行時,我的日誌中會出現大量錯誤,如下所示:

bayes: _put_token: SQL error: Incorrect string value: '\x8A\x98s\x9A\xC8' for column 'token' at row 1

我檢查了數據庫並進行了一些研究,發現這個非常古老的錯誤報告指出了這個問題:我的架構(非常!)過時了。該列bayes_token.tokenCHAR(5)排序規則 utf8_general_ci,截至 9 年前,應該是BINARY(5).

我不能簡單地轉換列類型,因為許多 UTF8 5-char 值長於 5 個字節(表有 ~110K 行)。

我的問題是:是否有任何方法可以截斷過長的標記,使它們在貝氏分類器中保持有效?或者如果失敗了,我可以只刪除那些行,以便我可以將其餘部分轉換為二進制?

更新:我確實設法將列內容傳輸到BINARY(5)表中的一個添加列(這裡命名為token2),如下所示:

UPDATE bayes_token SET token2 = CONVERT(token USING latin1);

這與我所能想到的“退回”插入時令牌發生的事情一樣接近。但是,結果列中有許多重複項,並且由於該token列是主鍵的一部分,這不好。

我認為數據可以保存,但可能不是純 SQL。我需要:

  1. 從最新模式創建空表的新副本
  2. 對每個標記的所有重複項進行分組,並將這些行的值ham_countspam_count最大值相加atime
  3. 將這些聚合結果插入到新表中
  4. 用新表替換原來的表

我相信我已經盡我所能重構了數據,如下所示。

  1. token2 BINARY(5) NOT NULL向表中添加列bayes_token
  2. UPDATE bayes_token SET token2 = CONVERT(token USING latin1);
  3. bayes_token2使用現代模式創建新表
  4. INSERT INTO bayes_token2 SELECT '1' AS id, token2 AS token, SUM(spam_count) AS spam_count, SUM(ham_count) AS ham_count, MAX(atime) AS atime FROM bayes_token GROUP BY token2;
  5. 刪除表bayes_token並替換為bayes_token2

絕大多數數據都是唯一的,無論如何在 UTF8 中不超過 5 個字節,但我認為我這樣做的方式也以正確的方式保存了其餘部分。

聽起來文本可能是不同的編碼。除非您首先轉換為 utf8mb4,否則您不能將不同的編碼放入單個列中。但是,如果你不知道編碼是什麼,那是不切實際的。

如果您的目標只是傳遞字節,我會使用VARBINARY(..)orBLOB這樣您就不會因字元集問題而絆倒。

在 MySQL 中,foo VARCHAR(5) CHARACTER SET utf8最多可以佔用 15 個字節。對於 utf8mb4,最多 20 個字節。所以VARBINARY(20),沒有CHARACTER SET

如果您的表目前包含foo在其中,以這種方式聲明,請執行

ALTER TABLE t
   MODIFY COLUMN foo BINARY(20);

(附加NULLNOT NULL酌情。)

引用自:https://serverfault.com/questions/1029024