我已实现了跟踪对数据库中存储的项目所做更改的功能。让我们看一下产品许可证,例如存储在表dp_tech_licence
(主键LicenceId
)中。
每当更改许可证时,更改都会存储在表格dp_tech_licence_history_mod
(主键ModificationId
),dp_tech_licence_history
(主键HistoryId
)和{{1} }(主键dp_history
)。 CollectionId
对于已更改的许可证的每个属性都有一行,并且具有引用dp_tech_licence_history_mod
的外键HistoryId
。对于每个已更改的许可,dp_tech_licence_history
都有一行,并且引用dp_tech_licence_history
的外键CollectionId
和引用dp_history
的外键LicenceId
。 dp_tech_licence
每次应用一项或多项更改时都有一行,并且外键dp_history
引用UserId
(表示执行更改的人员)。
例如,当为用户分配许可证时,dp_user
会更改。这将导致每个表dp_tech_licence.UserId
,dp_tech_licence_history_mod
和dp_tech_licence_history
中的一个新行。对于dp_history
中的新行,我们的值为dp_tech_licence_history_mod
和Property = 'UserId'
,其中Value = '<id>'
是用户的ID。
完成所有这些后,我想查看特定用户的许可证历史记录。具体来说,我想知道:
<id>
更改为用户的ID)dp_tech_licence.UserId
已从用户的ID更改为避免存储冗余数据,只有属性更改为的值存储在dp_tech_licence.UserId
中,而不是属性更改的值。因此,找出何时从用户移除许可证(上面的第2点)并不是直截了当的。我提出了以下问题,其中dp_tech_licence_history_mod
是用户的ID:
<id>
条件指出SELECT *
FROM dp_tech_licence_history_mod t1
LEFT JOIN dp_tech_licence_history t2 ON t2.`HistoryId` = t1.`HistoryId`
LEFT JOIN dp_history t3 ON t3.`CollectionId` = t2.`CollectionId`
WHERE t1.`Property` = 'UserId' AND ('<id>' = t1.`Value` OR '<id>' = (
SELECT t4.`Value`
FROM dp_tech_licence_history_mod t4
LEFT JOIN dp_tech_licence_history t5 ON t5.`HistoryId` = t4.`HistoryId`
LEFT JOIN dp_history t6 ON t6.`CollectionId` = t5.`CollectionId`
WHERE t4.`Property` = 'UserId' AND t5.`LicenceId` = t2.`LicenceId` AND t6.`ModifiedDate` < t3.`ModifiedDate`
ORDER BY t6.`ModifiedDate` DESC
LIMIT 1
))
ORDER BY t3.`ModifiedDate` DESC
是用户的ID,或者上次dp_tech_licence_history_mod.Value
已针对同一许可进行了更改,它已设置为用户的ID(这意味着它现在已从用户的ID更改为其他内容。
这个查询似乎工作正常,但它真的很慢!大约需要1.5秒,UserId
的行数少于20,000行。我想我已经添加了所有索引。以下是表格定义:
dp_tech_licence_history_mod
以下是运行CREATE TABLE `dp_tech_licence_history_mod` (
`ModificationId` bigint(32) NOT NULL AUTO_INCREMENT,
`HistoryId` bigint(32) NOT NULL,
`LocaleId` bigint(32) DEFAULT NULL,
`Property` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
`Value` text COLLATE utf8mb4_unicode_ci,
PRIMARY KEY (`ModificationId`),
KEY `dp_tech_licence_history_mod_History` (`HistoryId`),
KEY `dp_tech_licence_history_mod_Locale` (`LocaleId`),
KEY `dp_tech_licence_history_mod_Property` (`Property`),
CONSTRAINT `dp_tech_licence_history_mod_ibfk_1` FOREIGN KEY (`HistoryId`) REFERENCES `dp_tech_licence_history` (`HistoryId`),
CONSTRAINT `dp_tech_licence_history_mod_ibfk_2` FOREIGN KEY (`LocaleId`) REFERENCES `dp_locale` (`LocaleId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
CREATE TABLE `dp_tech_licence_history` (
`HistoryId` bigint(32) NOT NULL AUTO_INCREMENT,
`CollectionId` bigint(32) NOT NULL,
`TypeId` bigint(32) NOT NULL,
`LicenceId` bigint(32) NOT NULL,
PRIMARY KEY (`HistoryId`),
KEY `dp_tech_licence_history_Licence` (`LicenceId`),
KEY `dp_tech_licence_history_Collection` (`CollectionId`),
KEY `dp_tech_licence_history_Type` (`TypeId`),
CONSTRAINT `dp_tech_licence_history_Type` FOREIGN KEY (`TypeId`) REFERENCES `dp_history_type` (`TypeId`),
CONSTRAINT `dp_tech_licence_history_ibfk_2` FOREIGN KEY (`LicenceId`) REFERENCES `dp_tech_licence` (`LicenceId`),
CONSTRAINT `dp_tech_licence_history_ibfk_3` FOREIGN KEY (`CollectionId`) REFERENCES `dp_history` (`CollectionId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
CREATE TABLE `dp_history` (
`CollectionId` bigint(32) NOT NULL AUTO_INCREMENT,
`ModifierId` bigint(32) DEFAULT NULL,
`ModifiedDate` datetime NOT NULL,
`Uri` text COLLATE utf8mb4_unicode_ci,
PRIMARY KEY (`CollectionId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_unicode_ci
。
EXPLAIN
有没有人知道我如何才能提高跟踪更改的实施效果?