トップ回答者
文字列から一意のIDを生成したいです

質問
回答
-
皆様ありがとうございます。
>SELECT * FROM MyTable WHERE CONVERT(nvarchar, nTextColumn) = @nTextColumn
>ではだめでしょうか?nvarcharにキャストするとおそらくデータの末尾が切り捨てられてしまうので
正確な比較はできないかと思っています。また複数のnvarchar(max)のカラムを用意して、分割して入れるというのも
思いましたが、レコード数が増えてくると良くないと思ってやめました。Takaokaさんの言われていた、最初はMD5ハッシュで照合して、合致したら
全文で比較するという2段階で今回は解決したいと思います。
どうもありがとうございました。
すべての返信
-
haarp さんからの引用 調べてMD5CryptoServiceProvider().ComputeHash()を使用してみたのですが、
これでは一意にならないようです。
確実に一意になるような方法ありませんでしょうか?
一意っていうと、重複しないものですよね?
MD5は、あるものを与えると特定の法則で計算された別の結果を返すもので、同じものを与える限りは同じ結果が得られるのが仕様(ダイジェストやハッシュ)です。
従って、重複しない、一意のものを期待しているのであれば、そもそも用途が間違っています。
何をもって「一意」ということを期待しているかでも変わると思いますが、大抵のケースではGUIDである程度満足(容認)できるとは思います。
# 100%確実に重複しないという保障はないと思います。
# GUIDであっても、重複する確率が極めて低いだけで、絶対に重複しないわけではありません。
追記:
書いている間にレスが来てた。orz
-
haarp さんからの引用 今回はDBのntext型の一意性を確保したいと思っていて
それにハッシュ値の利用を考えています。
つまり、そのntext型のカラムの重複を許したくないと言うことですか?
# SQL Serverには疎いけど、ntext型のカラム自体にUNIQUE制約はかからないのかな…。
haarp さんからの引用 ntext型の文字列をハッシュ値にして
そのハッシュ値をDBのUNIQUE制約をかけたカラムに
保存することを考えています。
ハッシュである以上、程度の差はあれ、異なる入力が異なる結果になるとは限りません。
(ビット数が有限である以上、入力に制限がなければ、違う文字列で同じ結果になる可能性はある)
ハッシュで重複チェックし、重複していたら本当に同じかどうかを元の文字列でチェックするという高速化(枝狩り)にしかならないのでは?
やりたいことが限定されているのであれば、今の方針で容認できるのかもしれませんが、最初の「MD5では一意にならない」という発言から、今の方針じゃ駄目じゃないのかなという気がしてます。
-
haarp さんからの引用 最初に書けばよかったのですが、
今回はDBのntext型の一意性を確保したいと思っていて
それにハッシュ値の利用を考えています。
ntext型の文字列をハッシュ値にして
そのハッシュ値をDBのUNIQUE制約をかけたカラムに
保存することを考えています。
Strring クラスに GetHash メソッドがあったりしますけどね。
http://msdn.microsoft.com/ja-jp/library/system.string.gethashcode.aspx
-
haarp さんからの引用 今回はDBのntext型の一意性を確保したいと思っていて
それにハッシュ値の利用を考えています。
ntext型の文字列をハッシュ値にして
そのハッシュ値をDBのUNIQUE制約をかけたカラムに
保存することを考えています。
ハッシュ値は既に出ているように重複する確率が低いだけで、一意性は確保できません。どうしても一意にしたいのであれば、ハッシュ値に何かUNIQUEな文字列を追加するしかないでしょう。でも、これだとハッシュ値を求める意味が無くなってしまうのではないかと思います(UNIQUEな文字列だけで良いので)。
ところで、どのような目的で文字列から一意な値を作られたいのでしょうか? その目的によっては代替案があるかもしれません。
-
ありがとうございます。
>ntext型のカラム自体にUNIQUE制約はかからないのかな…。
かからないようです。varchar型ではできるのですが・・
>ハッシュで重複チェックし、重複していたら本当に同じかどうかを
>元の文字列でチェックするという高速化(枝狩り)にしかならないのでは?
そうなのですが、たとえばSELECT * FROM MyTable WHERE nTextColumn = @nTextColumn
などのクエリは以下のエラーが出ますので、ハッシュ値化してUNIQUE制約
で解決できないかと考えていました。
[Microsoft][ODBC SQL Server Driver][SQL Server]データ型 ntext と varchar は equal to 演算子では互換性がありません。
-
ありがとうございます。
>どのような目的で文字列から一意な値を作られたいのでしょうか?
>その目的によっては代替案があるかもしれません。
DBのntext型のカラムに文字列を入れていて、そのカラムを一意にしたいと
思っています。
nvarcharではサイズが足りないので、ntext型にしているのですが、
前記の様にntext型だとSELECT * FROM MyTable WHERE nTextColumn = @nTextColumn
のようなクエリでエラーがでますし、レコードが増えると検索時間もかかるようになります。
そのようなことで、考えてみた方法がntext型の文字列を重複チェック用にハッシュ値化するという
ことでした。
MD5CryptoServiceProviderを使ってみたのですが、一意にならないようです。
あとはDataSetに全レコードを吸い出してチェックするしかないのかも考えているのですが、
レコードが増えてくると現実的ではなくなってきますよね。
-
haarp さんからの引用 そのようなことで、考えてみた方法がntext型の文字列を重複チェック用にハッシュ値化するという
ことでした。
MD5CryptoServiceProviderを使ってみたのですが、一意にならないようです。
MD5 hashcode は、非UNIQUE INDEX に保持しておいて、コンフリクトが発生する場合のみ ntext 型のデータと全文比較するとよいのではないかと思います。このような方式で、実際に運用するデータの MD5 hashcode のコンフリクトの発生率と、発生した後に比較対象となる ntext 型のデータの行数を実際に確認するなり、試算するなりすると、ほとんどの場合で無視できる程度の回数の全文比較になると思います。逆に、MD5 によるチェックを行っても全文比較回数が 1% 以上もの高い確率で発生するような場合、ハッシュアルゴリズムを変更するとか、ハッシュ対象となる ntext 型の文章のハッシュ対象部分を調整するとかするとうまくいくことが多いと思います。 -
皆様ありがとうございます。
>SELECT * FROM MyTable WHERE CONVERT(nvarchar, nTextColumn) = @nTextColumn
>ではだめでしょうか?nvarcharにキャストするとおそらくデータの末尾が切り捨てられてしまうので
正確な比較はできないかと思っています。また複数のnvarchar(max)のカラムを用意して、分割して入れるというのも
思いましたが、レコード数が増えてくると良くないと思ってやめました。Takaokaさんの言われていた、最初はMD5ハッシュで照合して、合致したら
全文で比較するという2段階で今回は解決したいと思います。
どうもありがとうございました。