gpt4 book ai didi

mysql - Rails 关联有两个外键?

转载 作者:行者123 更新时间:2023-11-30 00:08:12 25 4
gpt4 key购买 nike

我对Rails很陌生,通过搜索找不到类似的情况。我有两个现有表 eventdata:

event 有很多很多列:

+-------------------+----------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+----------------------+------+-----+---------+-------+
| sid | int(10) unsigned | NO | MUL | NULL | |
| cid | int(10) unsigned | NO | | NULL | |
| signature | varchar(255) | NO | MUL | NULL | |
| src_ip | int(10) unsigned | YES | MUL | NULL | |
| dst_ip | int(10) unsigned | YES | MUL | NULL | |
| ... | ... | ... | ... | ... | |
| etc | | | | | |
+-------------------+----------------------+------+-----+---------+-------+

data 只有三个:

+--------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+------------------+------+-----+---------+-------+
| sid | int(10) unsigned | NO | MUL | NULL | |
| cid | int(10) unsigned | NO | | NULL | |
| data_payload | text | YES | | NULL | |
+--------------+------------------+------+-----+---------+-------+

我的模型:

class Event < ActiveRecord::Base
has_one :payload, :foreign_key => 'cid', :primary_key => 'cid'
self.table_name = "event";
[more stuff]
end

class Payload < ActiveRecord::Base
belongs_to :event
self.table_name = "data";
end

使用 has_one 关系,我可以执行如下查询:

Event.limit(5).offset(90000).each do |e|

然后循环并为每次迭代调用e.payload,这将执行如下查询:

SELECT  `data`.* FROM `data`  WHERE `data`.`cid` = 90001 LIMIT 1

但这显然不是正确的做法。我觉得我在这里打出这样的文字是在自取其辱。

我认为我理想的查询是这样的:

SELECT `event`.`cid`, `event`.`sid`, `event`.`signature`, `data`.`data_payload` 
FROM `event`, `data`
WHERE `event`.`sid` = `data`.`sid` AND
`event`.`cid` = `data`.`cid` AND
`event`.`signature` LIKE 'example_signature'

有没有一种方法可以通过正确的 Rails 关联在一个查询中完成这一切?只要想到将最终的 ActiveRecord/hash 对象传递到我的 View 所需要经历的过程,我就会觉得我正在以一种非常迂回的方式做这件事。

最佳答案

您的意思是,它不应该在每次传递时触发新的 SELECT 查询?

您可以使用 includes() 指令对此进行优化,如下所示:

events = Event.includes(:payload).where('signature LIKE ?', 'example_signature')
events.each do |event|
puts e.payload.data_payload
end

这将在 2 个查询中加载所有数据,一个查询用于所有事件,另一个查询用于所有具有返回事件的外键的有效负载:

Event Load (0.2ms)  SELECT "event".* FROM "event"  WHERE (signature LIKE 'example_signature')
Payload Load (0.2ms) SELECT "data".* FROM "data" WHERE "data"."cid" IN (2,4,5,6,7)

编辑:

您的评论似乎表明性能是对此最关心的问题(可能是因为表格很大),所以我认为您已经非常接近了。我建议只选择您需要的列(因为事件表有很多列),并使用 SQL JOIN 添加另一个表的内容以直接查询(因为存在一对一的关系)事件到负载的一种映射)

这将做到这一点:

Event.
select('event.cid, event.sid, event.signature, data.cid, data.sid, data.data_payload').
joins(:payload).
where('signature LIKE ?', 'example_signature').each do |event|
puts event.data_payload
end
# SELECT event.cid, event.sid, event.signature, data.cid, data.sid, data.data_payload FROM "event" INNER JOIN "data" ON "data"."cid" = "event"."cid" WHERE (signature LIKE 'example_signature')

这还将保留您的 Event 对象,因此您可以对其调用其他方法,但如果它们不依赖于您在 select() 中排除的属性> 条款。

如果您不需要 Event 对象中的任何其他方法,而只想尽快获得结果,那么您可以使用以下命令运行原始查询:

sanitized_str = ActiveRecord::Base.connection.quote('example_signature')
result = ActiveRecord::Base.connection.execute(
"SELECT event.cid, event.sid, event.signature, data.cid, data.sid, data.data_payload
FROM event
INNER JOIN data ON data.cid = event.cid
WHERE (signature LIKE #{sanitized_str});"
)
# => [{"cid"=>2, "sid"=>1, "signature"=>"example_signature", "data_payload"=>"Hello world!", 0=>2, 1=>1, 2=>"example_signature", 3=>2, 4=>1, 5=>"Hello world!"}]

这将返回一个记录数组,其中每个记录都是普通的 ruby​​ 哈希值。事件对象不会在内存中构建,从而节省大量开销。

关于mysql - Rails 关联有两个外键?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24331239/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com