none
文字列から一意のIDを生成したいです RRS feed

  • 質問

  • タイトルどおりですが、文字列から一意のIDを生成したいです。

    調べてMD5CryptoServiceProvider().ComputeHash()を使用してみたのですが、

    これでは一意にならないようです。

    確実に一意になるような方法ありませんでしょうか?

    2009年1月19日 12:35

回答

  • 皆様ありがとうございます。

    >SELECT * FROM MyTable WHERE CONVERT(nvarchar, nTextColumn) = @nTextColumn
    >ではだめでしょうか?

    nvarcharにキャストするとおそらくデータの末尾が切り捨てられてしまうので
    正確な比較はできないかと思っています。

    また複数のnvarchar(max)のカラムを用意して、分割して入れるというのも
    思いましたが、レコード数が増えてくると良くないと思ってやめました。

    Takaokaさんの言われていた、最初はMD5ハッシュで照合して、合致したら
    全文で比較するという2段階で今回は解決したいと思います。
    どうもありがとうございました。

    2009年1月21日 13:24

すべての返信

  • 文字列からではないですが

    Guidを使用しては如何でしょう。

     

    MSDN

        Guid 構造体

    NewGuid メソッド

    上記より引用

    | 重複する確率がかなり低くなっています。

     

    # MSDN調子わるい・・・

    2009年1月19日 14:37
  • ありがとうございます。

    一意性の確保としてGuidは良さそうですね。

    ただ、今回の私の目的には合わなさそうです。

     

    最初に書けばよかったのですが、

    今回はDBのntext型の一意性を確保したいと思っていて

    それにハッシュ値の利用を考えています。

    ntext型の文字列をハッシュ値にして

    そのハッシュ値をDBのUNIQUE制約をかけたカラムに

    保存することを考えています。

     

    このような場合、どのような方法が良いでしょうか?

    どうかよろしくお願いいたします。

    2009年1月19日 15:08
  •  haarp さんからの引用

    調べてMD5CryptoServiceProvider().ComputeHash()を使用してみたのですが、

    これでは一意にならないようです。

    確実に一意になるような方法ありませんでしょうか?

    一意っていうと、重複しないものですよね?

    MD5は、あるものを与えると特定の法則で計算された別の結果を返すもので、同じものを与える限りは同じ結果が得られるのが仕様(ダイジェストやハッシュ)です。

    従って、重複しない、一意のものを期待しているのであれば、そもそも用途が間違っています。

     

    何をもって「一意」ということを期待しているかでも変わると思いますが、大抵のケースではGUIDである程度満足(容認)できるとは思います。

     

    # 100%確実に重複しないという保障はないと思います。

    # GUIDであっても、重複する確率が極めて低いだけで、絶対に重複しないわけではありません。

     

     

     

    追記:

    書いている間にレスが来てた。orz

    2009年1月19日 15:18
    モデレータ
  •  haarp さんからの引用

    今回はDBのntext型の一意性を確保したいと思っていて

    それにハッシュ値の利用を考えています。

    つまり、そのntext型のカラムの重複を許したくないと言うことですか?

    # SQL Serverには疎いけど、ntext型のカラム自体にUNIQUE制約はかからないのかな…。

     

     haarp さんからの引用

    ntext型の文字列をハッシュ値にして

    そのハッシュ値をDBのUNIQUE制約をかけたカラムに

    保存することを考えています。

    ハッシュである以上、程度の差はあれ、異なる入力が異なる結果になるとは限りません。

    (ビット数が有限である以上、入力に制限がなければ、違う文字列で同じ結果になる可能性はある)

    ハッシュで重複チェックし、重複していたら本当に同じかどうかを元の文字列でチェックするという高速化(枝狩り)にしかならないのでは?

     

     

    やりたいことが限定されているのであれば、今の方針で容認できるのかもしれませんが、最初の「MD5では一意にならない」という発言から、今の方針じゃ駄目じゃないのかなという気がしてます。

    2009年1月19日 15:25
    モデレータ
  •  haarp さんからの引用

    最初に書けばよかったのですが、

    今回はDBのntext型の一意性を確保したいと思っていて

    それにハッシュ値の利用を考えています。

    ntext型の文字列をハッシュ値にして

    そのハッシュ値をDBのUNIQUE制約をかけたカラムに

    保存することを考えています。

    Strring クラスに GetHash メソッドがあったりしますけどね。

    http://msdn.microsoft.com/ja-jp/library/system.string.gethashcode.aspx

    2009年1月19日 23:40
  •  haarp さんからの引用

    今回はDBのntext型の一意性を確保したいと思っていて

    それにハッシュ値の利用を考えています。

    ntext型の文字列をハッシュ値にして

    そのハッシュ値をDBのUNIQUE制約をかけたカラムに

    保存することを考えています。

     

    ハッシュ値は既に出ているように重複する確率が低いだけで、一意性は確保できません。どうしても一意にしたいのであれば、ハッシュ値に何かUNIQUEな文字列を追加するしかないでしょう。でも、これだとハッシュ値を求める意味が無くなってしまうのではないかと思います(UNIQUEな文字列だけで良いので)。

    ところで、どのような目的で文字列から一意な値を作られたいのでしょうか? その目的によっては代替案があるかもしれません。

    2009年1月20日 1:08
    モデレータ
  • ありがとうございます。

    >ntext型のカラム自体にUNIQUE制約はかからないのかな…。

    かからないようです。varchar型ではできるのですが・・

     

    >ハッシュで重複チェックし、重複していたら本当に同じかどうかを

    >元の文字列でチェックするという高速化(枝狩り)にしかならないのでは?

    そうなのですが、たとえばSELECT * FROM MyTable WHERE nTextColumn = @nTextColumn

    などのクエリは以下のエラーが出ますので、ハッシュ値化してUNIQUE制約

    で解決できないかと考えていました。

     

    [Microsoft][ODBC SQL Server Driver][SQL Server]データ型 ntext と varchar は equal to 演算子では互換性がありません。

    2009年1月20日 3:19
  • ありがとうございます。

    >どのような目的で文字列から一意な値を作られたいのでしょうか? 

    >その目的によっては代替案があるかもしれません。

     

    DBのntext型のカラムに文字列を入れていて、そのカラムを一意にしたいと

    思っています。

    nvarcharではサイズが足りないので、ntext型にしているのですが、

    前記の様にntext型だとSELECT  * FROM MyTable WHERE nTextColumn = @nTextColumn

    のようなクエリでエラーがでますし、レコードが増えると検索時間もかかるようになります。

     

    そのようなことで、考えてみた方法がntext型の文字列を重複チェック用にハッシュ値化するという

    ことでした。

    MD5CryptoServiceProviderを使ってみたのですが、一意にならないようです。

     

    あとはDataSetに全レコードを吸い出してチェックするしかないのかも考えているのですが、

    レコードが増えてくると現実的ではなくなってきますよね。

     

    2009年1月20日 3:29
  •  

    > SELECT * FROM MyTable WHERE nTextColumn = @nTextColumn

    SELECT * FROM MyTable WHERE CONVERT(nvarchar, nTextColumn) = @nTextColumn

    ではだめでしょうか?

     

    #nvarcharにサイズを指定しないとまずいですかね?

    2009年1月20日 3:33
  •  haarp さんからの引用

    そのようなことで、考えてみた方法がntext型の文字列を重複チェック用にハッシュ値化するという

    ことでした。

     

    なるほど。重複チェック用だったんですね。私はこのような大きなサイズを重複チェックするようなことを行った経験がありませんので詳しくありませんが、ただ以下のことは言えます。

     

    1.SQL Server 2005以上だとnvarchar(max)を使うのが推薦。

    2.ntextには=は使えない。ただし、likeなどは使える。nvarchar(max)だと=が使える。

    2009年1月20日 7:15
    モデレータ
  •  haarp さんからの引用

    そのようなことで、考えてみた方法がntext型の文字列を重複チェック用にハッシュ値化するという

    ことでした。

    MD5CryptoServiceProviderを使ってみたのですが、一意にならないようです。


    MD5 hashcode は、非UNIQUE INDEX に保持しておいて、コンフリクトが発生する場合のみ ntext 型のデータと全文比較するとよいのではないかと思います。

    このような方式で、実際に運用するデータの MD5 hashcode のコンフリクトの発生率と、発生した後に比較対象となる ntext 型のデータの行数を実際に確認するなり、試算するなりすると、ほとんどの場合で無視できる程度の回数の全文比較になると思います。

    逆に、MD5 によるチェックを行っても全文比較回数が 1% 以上もの高い確率で発生するような場合、ハッシュアルゴリズムを変更するとか、ハッシュ対象となる ntext 型の文章のハッシュ対象部分を調整するとかするとうまくいくことが多いと思います。

    2009年1月21日 5:31
  • 皆様ありがとうございます。

    >SELECT * FROM MyTable WHERE CONVERT(nvarchar, nTextColumn) = @nTextColumn
    >ではだめでしょうか?

    nvarcharにキャストするとおそらくデータの末尾が切り捨てられてしまうので
    正確な比較はできないかと思っています。

    また複数のnvarchar(max)のカラムを用意して、分割して入れるというのも
    思いましたが、レコード数が増えてくると良くないと思ってやめました。

    Takaokaさんの言われていた、最初はMD5ハッシュで照合して、合致したら
    全文で比較するという2段階で今回は解決したいと思います。
    どうもありがとうございました。

    2009年1月21日 13:24