0

複数のテーブルが候補キー (例: ユーザー名) として文字列データを持ち、それに応じてインデックスが作成されるデータベースを実装しています。私が欲しいこれらのフィールドについて:

  1. 誰かがそれらのキーでテーブルをクエリするときの大文字と小文字の区別なし

  2. アプリケーションが元のケースを使用してユーザーにデータを表示できるように、最初に書き込まれたケースを何らかの方法で保存する必要があります。

また、アプリケーション コードは特定の RDBMS に依存しない (またはすべきでない) ため、データベース スキーマを可能な限りデータベースに依存しないようにしたいと考えています。

また、データベースで実行されるクエリの大部分は、クライアントによるテーブルへの直接アクセスではなく、アプリケーション コードによって実行されることにも注意してください。

これを実装する際に、私は多くの厄介な問題に遭遇しています。1 つは、すべての RDBMS が同じ方法で COLLATE を実装しているわけではないことです (大文字と小文字の区別がスキーマ レベルで調整可能であると思われる場合)。もう 1 つの問題は、照合順序と大文字と小文字の区別のオプションを複数のレベル (サーバー、データベース、テーブル (?)、列) で設定できるため、アプリケーションがどのような設定になるかを保証できないことです。さらに別の問題は、単に大文字と小文字を区別するだけでなく、COLLATE 自体が複雑になる可能性があることです (例: Unicode オプション)。

これらの頭痛の種をすべて回避するために、私が考えているのは、1 つのデータに対して 2 つの列を格納することで、この問題を完全に回避することです。1 つの列は元の大文字を使用し、もう 1 つの列はアプリケーション層によって小文字に変更されました。

例: テーブル内の 2 つのフィールド

user_name = "fredflintstone" (この一意のインデックス)
orig_name = "FredFlintstone" (データのみ...制約なし)

私が見ているように、これの長所と短所は次のとおりです。

長所:

  1. あいまいさはありません。アプリケーション コードが大文字と小文字の変換を管理し、基になる RDBMS/設定が変更されたときに単体テストが「不可解に」失敗することを心配する必要はありません。

  2. インデックスの検索はクリーンであり、照合機能や LOWER() などの呼び出しによって速度が低下することはありません (そのようなことがインデックスの速度を低下させると仮定すると、これは論理的に思われます)。

短所:

  1. 倍増したデータに必要な追加のストレージ容量

  2. ちょっと野蛮に見える

私はそれがうまくいくことを知っていますが、同時にそれは間違ったにおいがします.

これを行うのは非常識ですか/無意味ですか? 大文字と小文字の区別の問題を、現時点で私が思っているよりも簡単にする、私が知らない何かがありますか?

4

4 に答える 4

2

もちろん、このような決定は常にトレードオフですが、これが必ずしも「データの倍増」であるとは限りません。文字列を小文字にすることは、特にASCIIを超える場合、重要な操作になる可能性があるため、文字列の小文字バージョンは単に「重複」するだけではありません。元の文字列と多少関係がありますが、それ以上ではありません。

計算結果をDBに保存するのと類似していると考えると、より自然になります。

クエリを実行するオプションはUPPER(UserName)、2番目の列を回避するもう1つの優れたソリューションです。ただし、これを使用するには、少なくとも信頼性の高いUPPER関数(特に、非ASCII文字に使用するロケールを制御できる場合)と、適切なパフォーマンスを得るための関数ベースのインデックスが必要です。

于 2010-10-25T16:26:20.717 に答える
2

インデックスの検索はクリーンであり、照合機能や LOWER() などの呼び出しによって速度が低下することはありません (そのようなことがインデックスの速度を低下させると仮定すると、これは論理的に思われます)。

いいえ、それは論理的ではありません。定数関数にインデックスを付けることができます。

create index users_name on users(name); -- index on name
create index users_name_lower on users(lower(name)); -- index on the function result

RDBMS は、次のusers_name_lowerクエリを取得したときに使用できるほどスマートである必要があります。

select * from users where lower(name) = ?

users_name_lower がなければ、はい、テーブルを歩き回る必要があります。関数インデックスを使用すると、正しいことを行います。

于 2010-10-25T16:47:55.303 に答える
1

検索クエリを次のようにすることを提案します。

  • SELECT * FROM Users WHERE LOWER(UserName) = LOWER('fredFlinstone')
  • 大文字と小文字の区別を無視/尊重する必要がある場合は、クエリに COLLATION ヒントを明示的に含めます。

大文字と小文字を区別するためのデータの複製は面倒すぎると思います。

于 2010-10-25T16:26:00.903 に答える
1

パフォーマンス上の理由から、この方法でデータが複製されるのをよく見てきました。これにより、元のケーシングを保持できます (ケーシングがどうあるべきかを常に推測できるとは限らないため、明らかに必要になります。たとえば、各名前が大文字で始まるかどうかを確認することはできません)。データベースがこれを行う他の方法 (関数インデックス) をサポートしていない場合、これは実用的であり、クレイジーではありません。トリガーを使用すると、データの一貫性を保つことができます。

于 2010-10-25T16:33:14.270 に答える