【问题标题】:Do I need to explicitly index a foreign key if I index it with another column?如果我用另一列索引外键,是否需要显式索引它?
【发布时间】:2019-12-10 19:37:34
【问题描述】:

我正在经历这个例子:

class CreateArtworkShares < ActiveRecord::Migration[5.2]
  def change
    create_table :artwork_shares do |t|
      t.integer :artwork_id, null: false
      t.integer :viewer_id, null: false
      t.timestamps
    end
    add_index :artwork_shares, :artwork_id
    add_index :artwork_shares, :viewer_id
    add_index :artwork_shares, [:artwork_id, :viewer_id], unique: true
  end
end

我指的是这个 Stack Overflow 帖子:Index on multiple columns in Ruby on Rails

我有点困惑为什么这个例子中的解决方案显式索引 :artwork_id。使用 :artwork_id 和 :viewer_id (代码中索引的最后一行)的索引是否已经为 :artwork_id 创建了索引?而且我还想知道是否有一种简单的方法来决定最后一个索引行中列的顺序。我阅读了上面发布的 Stack Overflow 答案,但是关于这些列的顺序的解释对于我来说有点过于笼统,无法理解这个概念。

【问题讨论】:

    标签: ruby-on-rails indexing


    【解决方案1】:

    是否使用 :artwork_id 和 :viewer_id 进行索引(最后一行 代码中的索引)已经为 :artwork_id 建立了索引?

    没有。仅当您在两列上查询时才使用复合索引 - 这就是重点。它是组合的索引。

    irb(main):001:0> ArtworkShare.where(viewer_id: 1).explain
      ArtworkShare Load (0.8ms)  SELECT "artwork_shares".* FROM "artwork_shares" WHERE "artwork_shares"."viewer_id" = $1  [["viewer_id", 1]]
    => EXPLAIN for: SELECT "artwork_shares".* FROM "artwork_shares" WHERE "artwork_shares"."viewer_id" = $1 [["viewer_id", 1]]
                                               QUERY PLAN
    ------------------------------------------------------------------------------------------------
     Bitmap Heap Scan on artwork_shares  (cost=4.20..13.67 rows=6 width=40)
       Recheck Cond: (viewer_id = '1'::bigint)
       ->  Bitmap Index Scan on index_artwork_shares_on_viewer_id  (cost=0.00..4.20 rows=6 width=0)
             Index Cond: (viewer_id = '1'::bigint)
    (4 rows)
    
    irb(main):002:0> ArtworkShare.where(viewer_id: 1, artwork_id: 1).explain
      ArtworkShare Load (1.7ms)  SELECT "artwork_shares".* FROM "artwork_shares" WHERE "artwork_shares"."viewer_id" = $1 AND "artwork_shares"."artwork_id" = $2  [["viewer_id", 1], ["artwork_id", 1]]
    => EXPLAIN for: SELECT "artwork_shares".* FROM "artwork_shares" WHERE "artwork_shares"."viewer_id" = $1 AND "artwork_shares"."artwork_id" = $2 [["viewer_id", 1], ["artwork_id", 1]]
                                                           QUERY PLAN
    ------------------------------------------------------------------------------------------------------------------------
     Index Scan using index_artwork_shares_on_artwork_id_and_viewer_id on artwork_shares  (cost=0.15..8.17 rows=1 width=40)
       Index Cond: ((artwork_id = '1'::bigint) AND (viewer_id = '1'::bigint))
    (2 rows)
    

    而且这种迁移很好……很糟糕。

    class CreateArtworkShares < ActiveRecord::Migration[6.0]
      def change
        create_table :artwork_shares do |t|
          t.belongs_to :artwork, null: false, foreign_key: true
          t.belongs_to :viewer, null: false, foreign_key: true
          t.timestamps
        end
    
        add_index :artwork_shares, [:artwork_id, :viewer_id], unique: true
      end
    end
    

    这会在artwork_idviewer_id 上添加外键约束和索引。它还会创建bigint,而不是常规的整数列。

    我还想知道是否有一种简单的方法来决定最后一个索引行中列的顺序。

    没有。没有简单的方法。这取决于应用程序中的访问路径。

    【讨论】:

    • 那么为了决定排序,这篇文章把缩小行数最快的那个放在前面是什么意思?例如,如果一个艺术家不能拥有多个具有相同标题的艺术品,那么正确的顺序是:艺术品标题,然后是艺术家?如果我错了,请纠正我,但如果我要把艺术家放在第一位,那么它就必须浏览所有艺术家的作品。但如果我把标题放在第一位,它只会抓住艺术家作品的一小部分(重复的标题)。
    • 是的,这听起来很对。它不是我什至认为我真正了解自己的东西。 use-the-index-luke.com/sql/where-clause/the-equals-operator/…
    猜你喜欢
    • 1970-01-01
    • 2012-11-15
    • 1970-01-01
    • 1970-01-01
    • 2011-03-04
    • 2013-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多