このデザインがうまく拡張できないと思うので、このデザインを最適化する手助けが必要です。
背景情報
データベースは、ワークフローエンジンアプリ用です。 EnduserscreateTransactionswith differentattributes、and atransactionは、そのの(= /// =)サブセットに基づいて、一連のステップを実行しますattributes(現在subsetは3ですが、将来変更される可能性があります)。
ステップの番号と順序トランザクションは、私が定義したルートから来ますこれらのルートはほとんど変更されません。
これは、routeを見つけるために使用されるテーブルの構造です。
これはTransaction
テーブルのようになります。
CREATE TABLE `Transaction` (
`TID` int(11) NOT NULL AUTO_INCREMENT,
`Type` varchar(30) COLLATE utf8mb4_unicode_ci NOT NULL,
`WavPost` varchar(30) COLLATE utf8mb4_unicode_ci NOT NULL,
`EmployeeClass` char(1) COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`TID`)
)
これは、すべての可能なルート(route_vw
)
select
`d`.`facstaff` AS `facstaff`,
`f`.`waveposted` AS `waveposted`,
`h`.`tempreg` AS `tempreg`,
`j`.`step_name` AS `step_name`,
`i`.`route_step_id` AS `route_step_id`,
`i`.`route_id` AS `route_id`,
`i`.`step_id` AS `step_id`,
`i`.`ndx` AS `ndx`,
`i`.`on_time` AS `on_time`,
`i`.`behind` AS `behind`,
`i`.`late` AS `late`
from
(
(
(
(
(
(
(
(
`route_defn` `a`
join `fac_staff_list` `c` on(
(
`a`.`fac_staff_list_id` = `c`.`fac_staff_list_id`
)
)
)
join `fac_staff` `d` on(
(
`c`.`fac_staff_list_id` = `d`.`fac_staff_list_id`
)
)
)
join `wave_post_list` `e` on(
(
`a`.`wave_post_list_id` = `e`.`wave_post_list_id`
)
)
)
join `wave_post` `f` on(
(
`e`.`wave_post_list_id` = `f`.`wave_post_list_id`
)
)
)
join `temp_reg_list` `g` on(
(
`a`.`temp_reg_list_id` = `g`.`temp_reg_list_id`
)
)
)
join `temp_reg` `h` on(
(
`g`.`temp_reg_list_id` = `h`.`temp_reg_list_id`
)
)
)
join `route_step` `i` on(
(
`a`.`route_defn_id` = `i`.`route_id`
)
)
)
join `step_defn` `j` on(
(
`i`.`step_id` = `j`.`step_defn_id`
)
)
)
これは、(the)Transaction(s)のルートを見つける方法です。
select *
from `Transaction` `A`
join `route_vw` `B`
on (
(`B`.`facstaff` = `A`.`EmployeeClass`)
and (`B`.`waveposted` = `A`.`WavPost`)
and (`B`.`tempreg` = `A`.`Type`)
)
問題
Array
(
[EVENT_ID] => 4
[Duration] => 0.003877
[SQL_TEXT] => SELECT *
FROM Transaction A
INNER JOIN route_vw D on (
A.EmployeeClass = D.facstaff AND
A.WavPost = D.waveposted AND
A.Type = D.tempreg
)
[DIGEST_TEXT] => SELECT `d` . `facstaff` AS `facstaff` , `f` . `waveposted` AS `waveposted` , `h` . `tempreg` AS `tempreg` , `j` . `step_name` AS `step_name` , `i` . `route_step_id` AS `route_step_id` , `i` . `route_id` AS `route_id` , `i` . `step_id` AS `step_id` , `i` . `ndx` AS `ndx` , `i` . `on_time` AS `on_time` , `i` . `behind` AS `behind` , `i` . `late` AS `late` FROM ( ( ( ( ( ( ( ( `UchihaTigerTalent` . `route_defn` `a` JOIN `UchihaTigerTalent` . `fac_staff_list` `c` ON ( ( `a` . `fac_staff_list_id` = `c` . `fac_staff_list_id` ) ) ) JOIN `UchihaTigerTalent` . `fac_staff` `d` ON ( ( `c` . `fac_staff_list_id` = `d` . `fac_staff_list_id` ) ) ) JOIN `UchihaTigerTalent` . `wave_post_list` `e` ON ( ( `a` . `wave_post_list_id` = `e` . `wave_post_list_id` ) ) ) JOIN `UchihaTigerTalent` . `wave_post` `f` ON ( ( `e` . `wave_post_list_id` = `f` . `wave_post_list_id` ) ) ) JOIN `UchihaTigerTalent` . `temp_reg_list` `g` ON ( ( `a` . `temp_reg_list_id` = `g` . `temp_reg_list_id` ) ) ) JOIN
[NO_INDEX_USED] => 0
[NO_GOOD_INDEX_USED] => 0
[ROWS_AFFECTED] => 0
[ROWS_SENT] => 214
[ROWS_EXAMINED] => 820
)
これらの統計は、Transaction
に14行あるときに取得されました。に基づく ROWS_EXAMINED
この方法がうまくスケールアップするとは思いません。多くの行を調べる必要がないようにこれを書くより良い方法はありますか?
注: db-fiddle.com デモをアップロードしました。
更新1
質問-「1列の "* _list"テーブルがわかりません。」
回答-* _listsテーブルを使用すると、ルートを使用する必要がある値のセット/リストを指定して再利用できます。
例えば
ルート4(route_defn.route_defn_id = 4
)は、スタッフのトランザクションに適用されます。
ルート#5は、教員のトランザクションに適用されます。
Fac_staff_list_id = 3のルートは、教職員と職員の両方のトランザクションに適用できます。 * fac_staff_list_id = 3のルートはないことに注意してください。
このロジックと構造は、temp_reg_listとwave_post_listにも適用されます。
更新2
"1:manyマッピングでは中間テーブル(* _list)は必要ありません。fac_staffテーブルには列route_defn_idが必要です。介在するfac_staff_listを削除します。(他の1:many関係の場合は同じです。)"-@ rick-james
"EXPLAIN SELECT ...とSHOW CREATE TABLEを提供してください"-@ rick-james
以下の更新されたスキーマは、@ rick-jamesからの提案に基づいています。
show create view route_vw
CREATE ALGORITHM=MERGE DEFINER=`root`@`localhost` SQL SECURITY INVOKER VIEW `route_vw` AS select `fac_staff`.`facstaff` AS `facstaff`,`wave_post`.`waveposted` AS `waveposted`,`temp_reg`.`tempreg` AS `tempreg`,`route_step`.`route_step_id` AS `route_step_id`,`route_step`.`route_id` AS `route_id`,`route_step`.`step_id` AS `step_id`,`route_step`.`ndx` AS `ndx`,`route_step`.`on_time` AS `on_time`,`route_step`.`behind` AS `behind`,`route_step`.`late` AS `late` from ((((`route_defn` join `fac_staff` on((`route_defn`.`route_defn_id` = `fac_staff`.`route_defn_id`))) join `wave_post` on((`route_defn`.`route_defn_id` = `wave_post`.`route_defn_id`))) join `temp_reg` on((`route_defn`.`route_defn_id` = `temp_reg`.`route_defn_id`))) join `route_step` on((`route_defn`.`route_defn_id` = `route_step`.`route_id`)))
show create table route_defn
CREATE TABLE `route_defn` (
`route_defn_id` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`route_defn_id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
show create table fac_staff
CREATE TABLE `fac_staff` (
`fs_id` int(11) NOT NULL AUTO_INCREMENT,
`route_defn_id` int(11) NOT NULL,
`facstaff` varchar(1) COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`fs_id`),
UNIQUE KEY `route_defn_id` (`route_defn_id`,`facstaff`),
KEY `facstaff` (`facstaff`),
CONSTRAINT `fac_staff_ibfk_1` FOREIGN KEY (`route_defn_id`) REFERENCES `route_defn` (`route_defn_id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
show create table wave_post
CREATE TABLE `wave_post` (
`wp_id` int(11) NOT NULL AUTO_INCREMENT,
`route_defn_id` int(11) NOT NULL,
`waveposted` varchar(10) COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`wp_id`),
UNIQUE KEY `route_defn_id` (`route_defn_id`,`waveposted`),
KEY `waveposted` (`waveposted`)
) ENGINE=InnoDB AUTO_INCREMENT=36 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
show create table Transaction
CREATE TABLE `Transaction` (
`TID` int(11) NOT NULL AUTO_INCREMENT,
`Type` varchar(30) COLLATE utf8mb4_unicode_ci NOT NULL,
`RequestType` varchar(30) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`WavPost` varchar(30) COLLATE utf8mb4_unicode_ci NOT NULL,
`IncSupPosition` int(8) unsigned zerofill NOT NULL,
`IncSupEmplid` int(6) unsigned zerofill NOT NULL,
`Supervisor` varchar(55) COLLATE utf8mb4_unicode_ci NOT NULL,
`Phone` varchar(10) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`Location` varchar(200) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`HireMgrName` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL,
`HireMgrEmail` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
`Comment` varchar(1000) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`Title` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,
`SalaryStart` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL,
`PositionJustification` varchar(1500) COLLATE utf8mb4_unicode_ci NOT NULL,
`InternalComparison` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`AdditionalDuties` varchar(1000) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`ReducedTask` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`PositionNumber` int(8) unsigned zerofill DEFAULT NULL,
`StatePosition` varchar(8) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`JobReqID` varchar(8) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`JobCode` varchar(6) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`DepartmentID` int(4) unsigned zerofill NOT NULL,
`DepartmentName` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL,
`BudgetCenter` varchar(4) COLLATE utf8mb4_unicode_ci NOT NULL,
`FullPart` varchar(1) COLLATE utf8mb4_unicode_ci NOT NULL,
`StandardHours` float NOT NULL,
`IncumbentEmplid` int(6) unsigned zerofill DEFAULT NULL,
`IncumbentName` varchar(200) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`PreHireEscalate` int(11) NOT NULL DEFAULT ''1'',
`CountyCode` int(2) unsigned zerofill NOT NULL,
`StateCode` varchar(2000) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`EmployeeClass` char(1) COLLATE utf8mb4_unicode_ci NOT NULL,
`SubmittedBy` varchar(8) COLLATE utf8mb4_unicode_ci NOT NULL,
`TimeStamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`TID`),
UNIQUE KEY `TID` (`TID`,`Type`,`WavPost`,`EmployeeClass`),
KEY `BudgetCenter` (`BudgetCenter`),
KEY `HireMgrEmail` (`HireMgrEmail`),
KEY `SubmittedBy` (`SubmittedBy`),
KEY `Type` (`Type`),
KEY `EmployeeClass` (`EmployeeClass`),
KEY `WavPost` (`WavPost`),
KEY `Type_2` (`Type`,`WavPost`,`EmployeeClass`)
) ENGINE=InnoDB AUTO_INCREMENT=6380 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
show create table temp_reg
CREATE TABLE `temp_reg` (
`tr_id` int(11) NOT NULL AUTO_INCREMENT,
`route_defn_id` int(11) NOT NULL,
`tempreg` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`tr_id`),
UNIQUE KEY `route_defn_id` (`route_defn_id`,`tempreg`),
KEY `tempreg` (`tempreg`),
KEY `rotue_defn_id` (`route_defn_id`),
CONSTRAINT `temp_reg_ibfk_1` FOREIGN KEY (`route_defn_id`) REFERENCES `route_defn` (`route_defn_id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=84 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
show create table route_step
CREATE TABLE `route_step` (
`route_step_id` int(11) NOT NULL AUTO_INCREMENT,
`route_id` int(11) NOT NULL,
`step_id` int(11) NOT NULL,
`ndx` int(11) NOT NULL,
`on_time` tinyint(1) DEFAULT NULL,
`behind` tinyint(1) DEFAULT NULL,
`late` tinyint(1) DEFAULT NULL,
PRIMARY KEY (`route_step_id`),
UNIQUE KEY `route_id_2` (`route_id`,`step_id`,`ndx`),
KEY `step_id` (`step_id`),
KEY `ndx` (`ndx`),
KEY `route_id` (`route_id`),
CONSTRAINT `route_step_ibfk_1` FOREIGN KEY (`step_id`) REFERENCES `step_defn` (`step_defn_id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `route_step_ibfk_2` FOREIGN KEY (`route_id`) REFERENCES `route_defn` (`route_defn_id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=34 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
1つのルートは多くのfac_staffタイプに適用できます。
1:manyマッピングでは、中間テーブル(* _list)は必要ありません。 fac_staff
テーブルには、列route_defn_id
が必要です。間にあるfac_staff_list
を取り除きます。 (他の1:多くの関係についても同じです。)