mySQL多对多双向关系和查询

时间:2017-10-24 20:47:40

标签: php mysql database

我有一个包含各种对象类型的数据库,每个对象类型由两个三字母代码定义,不包括列表包括:

  • FIL - 文件(fil_files表)
  • TRA - Transactions(tra_transactions table)
  • COM - 评论(com_comments表)
  • 采购订单(po_purchase_orders表)

我有一个名为obj_rels的关系表,其中包含以下字段:

  • ID
  • pri_type
  • pri_type_id
  • sec_type
  • sec_type_id
  • effective_on
  • trashed_on
  • trashed_by

关系表目前有大约95,000条记录。

对象类型可以是pri_type或sec_type。例如,事务和文件可能是相关的,因此TRA可能是主要的,而FIL则是次要的。或者文件和注释可能是相关的,因此在这种情况下文件FIL可能是主要的,而COM辅助。

所以我需要一个查询来拉取,例如,与文件相关的所有内容。

我正在做的是:

SELECT pri_type, pri_type_id, sec_type, sec_type_id, effective_on
FROM obj_rels 
WHERE ( trashed_on = 0 OR ISNULL(trashed_on) ) AND pri_type = 'FIL' AND pri_type_id = 1234
UNION
SELECT sec_type, sec_type_id, pri_type, pri_type_id, effective_on
FROM obj_rels
WHERE ( trashed_on = 0 OR ISNULL(trashed_on) ) AND sec_type = 'FIL' AND sec_type_id = 1234

对于像这样的一次性选择,它并不太糟糕。但是,当我执行更大的查询时,说我需要所有事务以及与每个单独事务相关的文件数量,这些查询会大大减慢我的Web应用程序的运行速度。我目前正在处理的查询在大约0.4秒内运行而没有文件&注释计数,计数约2.1秒。这是我试图写的查询的简化版本:

SELECT *
FROM tra_transactions AS tra
LEFT JOIN ( 
    SELECT pri_type, pri_type_id, COUNT(sec_type_id) AS cts
    FROM (
        SELECT pri_type, pri_type_id, sec_type, sec_type_id, effective_on
        FROM obj_rels WHERE pri_type = 'TRA' AND sec_type = 'FIL' AND ( trashed_on = 0 OR ISNULL(trashed_on) ) AND effective_on <= NOW()
        UNION
        SELECT sec_type, sec_type_id, pri_type, pri_type_id, effective_on
        FROM obj_rels WHERE sec_type = 'TRA' AND pri_type = 'FIL' AND ( trashed_on = 0 OR ISNULL(trashed_on) ) AND effective_on <= NOW()
    ) as qry 
    GROUP BY pri_type, pri_type_id
) AS rel ON rel.pri_type_id = tra.id
WHERE tra.ent_id = 40

是否有更好的方法来构建关系表以获得联盟和我需要运行的子查询?

我想知道每个关系是否更好地存储两个条目,以便每个类型的记录类型为主要和次要而不是一起运行多个查询?这会使表的大小加倍,那么运行连接查询会更有效吗?有更好的架构吗?

提前致谢!

...评论......我被要求提供索引。这是obj_rels表的Create语句......我不太擅长索引,所以我可能做了一些过度杀伤:

CREATE TABLE `obj_rels` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `pri_type` varchar(3) DEFAULT NULL,
  `pri_type_id` int(11) DEFAULT NULL,
  `sec_type` varchar(3) DEFAULT NULL,
  `sec_type_id` int(11) DEFAULT NULL,
  `effective_on` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `trashed_by` int(11) DEFAULT NULL,
  `trashed_on` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `types` (`pri_type`,`sec_type`),
  KEY `pri_type` (`pri_type`),
  KEY `pri_type_id` (`pri_type_id`),
  KEY `sec_type` (`sec_type`),
  KEY `sec_type_id` (`sec_type_id`),
  KEY `trashed_on` (`trashed_on`),
  KEY `pri_type_id_2` (`pri_type_id`,`pri_type`,`trashed_on`),
  KEY `sec_type_id_2` (`sec_type_id`,`sec_type`,`trashed_on`)
) ENGINE=InnoDB AUTO_INCREMENT=94530 DEFAULT CHARSET=utf8;

0 个答案:

没有答案