web-dev-qa-db-ja.com

ワークフローエンジンデータベースの設計の最適化

このデザインがうまく拡張できないと思うので、このデザインを最適化する手助けが必要です。

背景情報

データベースは、ワークフローエンジンアプリ用です。 EnduserscreateTransactionswith differentattributes、and atransactionは、そのの(= /// =)サブセットに基づいて、一連のステップを実行しますattributes(現在subsetは3ですが、将来変更される可能性があります)。

ステップ番号順序トランザクションは、私が定義したルートから来ますこれらのルートはほとんど変更されません。

これは、routeを見つけるために使用されるテーブルの構造です。

Route Structure

これは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テーブルを使用すると、ルートを使用する必要がある値のセット/リストを指定して再利用できます。

例えば

enter image description hereenter image description here

ルート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からの提案に基づいています。

enter image description here

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
3
bassxzero

1つのルートは多くのfac_staffタイプに適用できます。

1:manyマッピングでは、中間テーブル(* _list)は必要ありません。 fac_staffテーブルには、列route_defn_idが必要です。間にあるfac_staff_listを取り除きます。 (他の1:多くの関係についても同じです。)

1
Rick James