2015-04-06 54 views
0

我设计了一个以短链接为中心的数据库。Rails基于行的数据库,巨大的请求数

我有以下模式:

create_table "students", force: :cascade do |t| 
    t.string "first_name" 
    t.string "last_name" 
    t.string "email" 
    t.boolean "recruit", default: true 
    t.boolean "archive", default: false 
    t.datetime "created_at" 
    t.datetime "updated_at" 
    end 

    create_table "fields", force: :cascade do |t| 
    t.string "name" 
    t.integer "index" 
    t.integer "group_id" 
    t.string "description" 
    t.string "options" 
    t.boolean "hidden" 
    t.boolean "locked",  default: false 
    t.datetime "created_at" 
    t.datetime "updated_at" 
    end 

    create_table "groups", force: :cascade do |t| 
    t.string "name" 
    t.datetime "created_at" 
    t.datetime "updated_at" 
    end 

    create_table "texts", force: :cascade do |t| 
    t.integer "student_id" 
    t.integer "field_id" 
    t.string "content", default: "" 
    t.datetime "created_at" 
    t.datetime "updated_at" 
    end 

    create_table "options", force: :cascade do |t| 
    t.integer "student_id" 
    t.integer "field_id" 
    t.string "choice",  default: "" 
    t.datetime "created_at" 
    t.datetime "updated_at" 
    end 

    create_table "addresses", force: :cascade do |t| 
    t.integer "student_id" 
    t.integer "field_id" 
    t.string "address_1", default: "" 
    t.string "address_2", default: "" 
    t.string "city",  default: "" 
    t.integer "state_id", default: 1 
    t.string "zip",  default: "" 
    t.datetime "created_at" 
    t.datetime "updated_at" 
    end 

这个组织背后的基础是一个完全灵活的形式。您只需在字段表中添加一个新行,并且该条目在生成学生的表单上定义了一个新问题。组引用选项字段,文本字段或地址。保存数据时,与给定字段关联的组会告诉我的应用程序将哪个表放入。此系统运行良好。这是非常灵活的,我可以很容易地看到学生有什么数据的某些选项,我可以基于几乎任何东西进行查询。

问题是当我开始显示学生。我首先查询我想要展示的学生,然后我必须搜索每个学生的每个领域。这意味着对于500名学生,我基本上有大约2500条查询。这会杀死性能。

我想知道什么最好的方式来加入查询在一起,加快这个系统是?

部分原因是我不能100%确定学生有给定的字段,所以当我现在查询时,如果数据库没有返回任何结果,我可以创建一个。

回答

0

它不会显示好像你有任何外键这里定义。使用FK并确保它们在每个表上使用索引的组合应允许快速连接。

我假设你正在使用ActiveRecord的基于Rails的DSL在你的问题。一旦你添加了FK,我会建议你考虑使用joinsActiveRecord Querying doc

如果你担心某种JOIN列不存在,你可以使用LEFT OUTER JOIN从左侧表中调用(在上面的链接提到),以joins,这样你仍然可以得到所有的行,即使有在连接条件中没有匹配,只需获得右侧的NULL列值。那些是NULL会告诉你哪些不存在,可能需要随后创建。响应

编辑从OP评论:

我没有用的SchemaPlus宝石,不过我觉得这很好使用外键,如果你想,因为这是的事情之一它支持(根据its doc)。

对于这个问题:

等有致认为它是如果 某种原因,数据不再一端存在的外键的问题?

外键对执行referential integrity至关重要。

例如,如果你有field_id作为texts表的外键,你不能删除从field表中相应的记录(不使用cascade删除下游记录为好),因为它指的是记录在field

在另一面,你就无法插入texts一排无效field_id - 如果field_id没有在fields存在,的Postgres会抛出一个外键约束违反

外键是表设计的关键部分,绝对应该使用。它使您无需将所有逻辑都放在应用程序代码中的所有位置,例如在尝试插入任何内容之前,必须检查您要插入的键是否有效;相反,如果它们不是,Postgres将违反约束条件,并作为可处理的异常(例如回滚和返回错误)返回到您的应用程序。

基本上,任何时候你在一个表中引用另一个表中的记录时,都应该在外键约束中定义一个id。

此外,它可能值得添加一个主键到每个表。我经常喜欢使用serial变量来确保每一行都可以通过一个键来识别,即使存在形成隐含主键的元组。主键也隐式创建基于这些键的索引。

+0

嗨。我一直在研究SchemaPlus gem,并且似乎将外部约束作为一个简单的惯例添加到我的迁移中。只是把我打算成为外键的所有列正式列出来,是否有任何问题?如果由于某种原因导致数据在一端停止存在,那么认为它是一个外键会导致问题吗?我有一些行会引用我的主用户表,并且可能是一个键,但它们也可以被删除。外键会导致删除中的连锁反应吗? – 2015-04-08 03:38:03