MySQLのInnoDBテーブルには、base64でエンコードされた小さなjavascriptファイルの約10列と、base64でエンコードされたpng(<2KBサイズ)画像も保持されています。
挿入数は少なく、読み取りも比較的多いですが、その後の読み取りを避けるために、出力はMemcachedインスタンスに数分間キャッシュされます。
現在、これらの列にBLOB
を使用していますが、パフォーマンスまたはスナップショットのバックアップの観点からTEXT
データ型に切り替えることには利点があるのでしょうか。
私の検索結果は、私のケースのBLOB
とTEXT
がほぼ同じであることを示しており、実際にどのタイプのデータが実際に保存されるのか事前にわからないので、BLOB
。
この特定のケースに対するTEXT対BLOBの議論についての指針はありますか?
Base64は、印刷可能なテキスト文字のみを使用して任意のバイナリデータを表す方法です。これは、印刷可能なテキストのみを処理できるプロトコルまたはメディア(SMTP /電子メールなど)を介してそのようなバイナリデータを転送する必要がある状況向けに設計されました。データサイズが増加し(33%増加)、エンコード/デコードの計算コストが増えるため、どうしても必要な場合以外は避けてください。
対照的に、BLOB
列の重要な点は、生のバイナリ文字列を格納することです。先に進んで、最初のBase64エンコードを行わずに、直接BLOB
列にデータを保存してください。通常、ファイルバージョン/最終更新日、メディアタイプ、(JavaScriptソースなどのテキストファイルの場合は)文字エンコーディングなど、関連するメタデータを他の列に格納します。 MySQLが文字エンコーディングをネイティブに追跡するだけでなく、代替文字セットにトランスコードしたり、テキストを検査/操作したりできるように、テキストファイルにTEXT
タイプの列を使用することもできます。必要に応じて(現在または将来)。
SQLデータベースが任意のバイナリデータを処理するためにBase64のような印刷可能なテキストエンコーディングを必要とするという(誤った)考えは、多くの誤った情報に基づくチュートリアルによって永続化されています。この考えは、SQLは他のコンテキストでは印刷可能なテキストのみで構成されるため、バイナリデータに対しても(少なくともデータ転送ではなくデータ転送のために)確実にそれを必要とするという誤った考えに基づいているようです。これは単に真実ではありません。SQLは、プレーン文字列リテラル(他の文字列と同様に適切に引用符で囲まれ、エスケープされている場合)を含む、さまざまな方法でバイナリデータを伝達できます。もちろん、データベースに(任意のタイプの)データを渡すための推奨される方法は、パラメーター化されたクエリを使用する方法です。パラメーターには、他のデータと同じくらい簡単にバイナリデータを含めることができます。
それだけの価値があるので、私は通常、このようなアイテムをRDBMSに保存することを完全に避け、代わりにfilesystemsと呼ばれる高度に最適化されたファイルストレージデータベースを使用することを好みますが、それはまったく別の問題です。
Base64でエンコードされたデータを保存することでメリットがある唯一の状況は、データベースからデータが頻繁に取得され、そのエンコードを必要とするプロトコルを介して送信される場合です。この場合、Base64でエンコードされた表現を保存すると、フェッチのたびに、それ以外の場合は未処理のデータに対してエンコード操作を実行します。
ただし、この意味では、Base64でエンコードされたストレージはキャッシュとして機能するだけであり、パフォーマンス上の理由で非正規化データを格納する場合と同様です。
TEXT
ではなくBLOB
である必要があります上記で言及したように、TEXT
とBLOB
の違いは、実際にはTEXT
列がテキスト固有のメタデータ(文字エンコーディングおよびcollation)に対して、BLOB
列はそうではありません。この追加のメタデータにより、MySQLはストレージと接続の文字セット(適切な場合)間で文字をトランスコードし、空想的な文字の同等性/順序付けを実行できます。
一般的に言えば、異なる文字セットで動作する2つのクライアントが同じbytesを表示する必要がある場合は、BLOB
列が必要です。同じ文字が表示される場合は、TEXT
列が必要です。
Base64では、これら2つのクライアントは、最終的にデータが同じbytesにデコードされることを検出する必要があります。ただし、エンコードされたデータには同じ文字が含まれていることがわかります。たとえば、'Hello world!'
('SGVsbG8Gd29ybGQh'
)のBase64エンコーディングを挿入したいとします。挿入アプリケーションがUTF-8文字セットで機能している場合、バイトシーケンス0x53475673624738676432397962475168
がデータベースに送信されます。
そのバイトシーケンスがBLOB
列に格納され、UTF-16で動作するアプリケーションによって後で取得される場合*、同じバイトが返されます。これは'升噳扇㡧搲㥹扇全'
を表し、目的のBase64エンコード値ではありません。一方
そのバイトシーケンスがTEXT
列に格納され、後でUTF-16で動作するアプリケーションによって取得された場合、MySQLはオンザフライでトランスコードしてバイトシーケンス0x0053004700560073006200470038006700640032003900790062004700510068
を返します。これは、必要に応じて、元のBase64エンコード値'SGVsbG8Gd29ybGQh'
。
もちろん、それでもBLOB
列を使用して、他の方法で文字エンコードを追跡することはできますが、メンテナンスが複雑になり、意図しないエラーが発生するリスクがあるため、不必要にホイールを再発明します。
*実際には、MySQLは、ASCIIとバイト互換性のないクライアント文字セットの使用をサポートしていません(したがって、Base64エンコーディングは、それらのすべての組み合わせで常に一貫しています)。ただし、この例は、 BLOB
とTEXT
の列タイプの違いを示し、TEXT
が実際にエラーなしで機能するにもかかわらず、BLOB
がこの目的のために技術的に正しい理由を説明します( MySQLが非ASCII互換のクライアント文字セットのサポートを追加するまでは最低限です)。