sql >> データベース >  >> RDS >> PostgreSQL

一意のインデックスの違いを説明し、validates_uniqueness_of

    一意のインデックスとvalidates_uniqueness_of

    の違いは次のとおりです。

    これは、ActiveRecordがdbで生成された一意の制約違反のエラーを識別できるようにするパッチです。たとえば、validates_uniqueness_ofを宣言せずに次の作業を行います:

    create_table "users" do |t|
      t.string   "email",   null: false
    end
    add_index "users", ["email"], unique: true
    
    class User < ActiveRecord::Base
    end
    
    User.create!(email: '[email protected]')
    u = User.create(email: '[email protected]')
    u.errors[:email]
    => "has already been taken"
    

    利点は、スピード、使いやすさ、完全性です-

    速度

    このアプローチでは、保存時に一意性をチェックするためにdbルックアップを実行する必要はありません(インデックスが欠落していると非常に遅くなることがあります- https://rails.lighthouseapp.com/projects/8994/tickets/2503-validate .. 。 )。一意性の検証に本当に関心がある場合は、とにかくデータベース制約を使用する必要があります。これにより、データベースは何があっても一意性を検証し、このアプローチによって余分なクエリが削除されます。インデックスを2回チェックすることは、DBにとって問題ではありません(2回目にキャッシュされます)が、アプリケーションからのDBラウンドトリップを節約することは大きなメリットです。

    使いやすさ

    とにかく真の一意性のためにdb制約が必要であることを考えると、このアプローチでは、db制約が設定されると、すべてが自動的に実行されます。必要に応じて、validates_uniqueness_ofを引き続き使用できます。

    完全性

    validates_uniqueness_ofは常にちょっとしたハックでした。競合状態を適切に処理できず、多少冗長なエラー処理ロジックを使用して処理する必要のある例外が発生します。 ( http://api.rubyonrailsの「同時実行性と整合性」セクションを参照してください。 .org / classes / ActiveRecord / Validations / ClassMe ...

    validates_uniqueness_of 値の一意性を保証するには不十分です。この理由は、本番環境では、複数のワーカープロセスが競合状態を引き起こす可能性があるためです。

    1. 2つの同時リクエストが同じ名前のユーザーを作成しようとします(ユーザー名を一意にする必要があります)

    2. リクエストはサーバー上で2つのワーカープロセスによって受け入れられ、2つのワーカープロセスが並行して処理します

    3. どちらのリクエストもusersテーブルをスキャンして、名前が使用可能であることを確認します

    4. どちらのリクエストも検証に合格し、一見利用可能な名前のユーザーを作成します

    より明確に理解するには、これを確認してください

    列に一意のインデックスを作成すると、その列に同じ値を持つ複数の行がテーブルに含まれないことが保証されます。モデルでvalidates_uniqueness_of検証のみを使用するだけでは、同じデータを作成しようとする同時ユーザーが存在する可能性があるため、一意性を強制するのに十分ではありません。

    2人のユーザーが、ユーザーモデルにvalidates_uniqueness_of:emailを追加した同じ電子メールでアカウントを登録しようとしていると想像してください。同時に[登録]ボタンを押すと、Railsはユーザーテーブルでそのメールを探し、すべてが正常であり、レコードをテーブルに保存しても問題がないことを返信します。 Railsは、2つのレコードを同じ電子メールでユーザーテーブルに保存します。これで、対処すべき非常に厄介な問題が発生します。

    これを回避するには、データベースレベルでも一意の制約を作成する必要があります。

    class CreateUsers < ActiveRecord::Migration
      def change
        create_table :users do |t|
          t.string :email
          ...
        end
        
        add_index :users, :email, unique: true
      end
    end
    

    したがって、index_users_on_email固有のインデックスを作成することにより、2つの非常に優れた利点が得られます。一意のインデックスは非常に高速になる傾向があるため、データの整合性と優れたパフォーマンス。

    user_idの投稿テーブルにunique:trueを指定すると、同じuser_idで重複するレコードを入力できなくなります。



    1. GROUPBYクエリを使用したパーセンテージの計算

    2. mysql recursive(tree)親子カテゴリ

    3. ユーザーを登録する前に年齢を検証し、MVCを使用して特定の年齢を超えているかどうかを確認します

    4. 原因:java.lang.ClassNotFoundException:oracle.jdbc.OracleDriver