21

MySQL InnoDBテーブルには、base64でエンコードされた小さなjavascriptファイルの最大10列と、base64でエンコードされたpng(<2KBサイズ)画像も含まれています。

挿入は少なく、読み取りは比較的多いですが、その後の読み取りを避けるために、出力はMemcachedインスタンスに数分間キャッシュされます。

現在、これらの列に使用していますが、パフォーマンスやスナップショットのバックアップの観点から、データ型にBLOB切り替えることに利点があるのではないかと思います。TEXT

私の検索ではBLOBTEXT私の場合はほぼ同じであり、実際にどのタイプのデータが保存されるのかが事前にわからないため、に行きましたBLOB

この特定のケースについて、TEXTとBLOBの議論について何かアドバイスはありますか?

4

1 に答える 1

54

Base64でエンコードされたデータをデータベースに保存しないでください...

Base64は、任意のバイナリデータが印刷可能なテキスト文字のみを使用して表されるコーディングです。このようなバイナリデータを、印刷可能なテキスト(SMTP /電子メールなど)のみを処理できるプロトコルまたはメディアを介して転送する必要がある状況向けに設計されました。データサイズが(33%)増加し、エンコード/デコードの計算コストが増えるため、どうしても必要な場合を除いて、これは避ける必要があります。

対照的に、列の要点は、BLOB不透明なバイナリ文字列を格納することです。BLOBしたがって、最初にBase64でエンコードせずに、列に直接保存してください。(とはいえ、MySQLが保存されている特定のデータに適したタイプである場合は、代わりにそれを使用することをお勧めします。たとえば、JavaScriptソースなどのテキストファイルは、TEXTMySQLがテキスト固有のメタデータをネイティブに追跡する列に保存することでメリットが得られます。 —これについては以下で詳しく説明します)。

SQLデータベースが任意のバイナリデータを処理するためにBase64のような印刷可能なテキストエンコーディングを必要とするという(誤った)考えは、多くの情報不足のチュートリアルによって永続化されています。このアイデアは、SQLは他のコンテキストでは印刷可能なテキストのみで構成されているため、バイナリデータにも必ず必要であるという誤った考えに基づいているようです(少なくともデータ転送では、データストレージではない場合)。これは単純に真実ではありません。SQLは、プレーンな文字列リテラルを含むさまざまな方法でバイナリデータを伝達できます(他の文字列と同様に適切に引用符で囲まれ、エスケープされている場合)。もちろん、(任意のタイプの)データをデータベースに渡すための推奨される方法は、パラメーター化されたクエリを使用することです。パラメーターのデータ型は、他のものと同じように簡単に生のバイナリ文字列にすることができます。

...パフォーマンス上の理由でキャッシュされていない限り...

Base64でエンコードされたデータを保存することでメリットが得られる唯一の状況は、データベースから取得した直後に、そのようなエンコードを必要とするプロトコルを介してデータが送信される場合です。この場合、Base64でエンコードされたデータを保存します。表現は、フェッチのたびに生データに対してエンコード操作を実行する必要がなくなります。

ただし、この意味で、Base64でエンコードされたストレージは、パフォーマンス上の理由で非正規化されたデータを格納するのと同じように、単にキャッシュとして機能していることに注意してください。

...その場合はそうではありTEXTませんBLOB

上で示唆したように、と列の唯一の違いはTEXT、列の場合、MySQLがテキスト固有のメタデータ(文字エンコード照合など)を追加で追跡することです。この追加のメタデータにより、MySQLはストレージと接続文字セット(適切な場合)の間で値を変換し、高度な文字列の比較/並べ替え操作を実行できます。BLOBTEXT

一般的に言えば、異なる文字セットで動作する2つのクライアントが同じバイトを表示する必要がある場合は、BLOB列が必要です。同じ文字TEXTが表示される場合は、列が必要です。

Base64では、これら2つのクライアントは、データが同じバイトにデコードされることを最終的に検出する必要があります。ただし、保存/エンコードされたデータが同じ文字であることがわかります。たとえば、'Hello world!'(である'SGVsbG8gd29ybGQh')のBase64エンコーディングを挿入したいとします。挿入アプリケーションがUTF-8文字セットで動作している場合は、バイトシーケンス0x53475673624738676432397962475168をデータベースに送信します。

  • そのバイトシーケンスがBLOB列に格納され、後でUTF-16 *で動作しているアプリケーションによって取得された場合、同じバイトが返されます。これ'升噳扇㡧搲㥹扇全'は、目的のBase64エンコード値ではなくを表します。一方

  • そのバイトシーケンスがTEXT列に格納され、後でUTF-16で動作しているアプリケーションによって取得された場合、MySQLはオンザフライでトランスコードしてバイトシーケンスを返します。これは、必要に応じ0x0053004700560073006200470038006700640032003900790062004700510068て元のBase64エンコード値'SGVsbG8gd29ybGQh'を表します。

もちろん、それでもBLOB列を使用して文字エンコードを他の方法で追跡することはできますが、それでも不必要に車輪の再発明が行われ、メンテナンスが複雑になり、意図しないエラーが発生するリスクがあります。


BLOB*実際、MySQLはASCIIとバイト互換性のないクライアント文字セットの使用をサポートしていません(したがって、Base64エンコーディングはそれらの任意の組み合わせで常に一貫しています)が、この例は、列タイプとTEXT列タイプの違いを説明するのに役立ちます。実際にはエラーなしで機能するにもかかわらず(少なくともMySQLが非ASCII互換のクライアント文字セットのサポートを追加するまで)TEXT、この目的に対して技術的に正しい理由を説明します。BLOB

于 2012-12-26T15:39:03.730 に答える