2013-04-30 53 views
1

我還在學習MySQL,所以請忍受我...多列上的MySQL外鍵?

我有幾個表(下面概述),我想記錄錯誤消息。我不是指查詢錯誤,而只是我的消息,如「連接到站點失敗」,「在站點xyz卡讀取錯誤」等...

我想到有一個表「error_logs」跟蹤我的錯誤,只有三列:

  • ID
  • ERROR_MESSAGE
  • IS_ACTIVE

我遇到的問題,然而,就是每個錯誤會涉及到創紀錄在'卡','門'或'網站'表,我想跟蹤消息屬於哪條記錄(來自各種表格)。

所以,我的問題是什麼將是最好的方法來解決這個問題?我曾考慮添加兩個額外的列,'record_id'(它將引用另一個表中的一個id)和'table'(它將跟蹤消息所屬的表)。另外,另一個警告是,很可能會有額外的「主要」表格。

這裏是我迄今表:

CREATE TABLE `statuses` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `name` varchar(45) NOT NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1$$; 

INSERT INTO statuses SET name = 'error'; 
INSERT INTO statuses SET name = 'pre-install'; 
INSERT INTO statuses SET name = 'validate'; 
INSERT INTO statuses SET name = 'active'; 
INSERT INTO statuses SET name = 'disabled'; 

CREATE TABLE `sites` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `name` varchar(45) NOT NULL, 
    `status_id` int(11) NOT NULL, 
    PRIMARY KEY (`id`), 
    KEY `sites_status_id_idx` (`status_id`), 
    CONSTRAINT `sites_status_id` FOREIGN KEY (`status_id`) REFERENCES `statuses` (`id`) ON UPDATE CASCADE 
) ENGINE=InnoDB DEFAULT CHARSET=latin1$$; 

CREATE TABLE `doors` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `description` varchar(255) NOT NULL, 
    `site_id` int(11) NOT NULL, 
    `status_id` int(11) NOT NULL, 
    PRIMARY KEY (`id`), 
    KEY `doors_site_id_idx` (`site_id`), 
    KEY `doors_status_id_idx` (`status_id`), 
    CONSTRAINT `doors_status_id` FOREIGN KEY (`status_id`) REFERENCES `statuses` (`id`) ON UPDATE CASCADE, 
    CONSTRAINT `doors_site_id` FOREIGN KEY (`site_id`) REFERENCES `sites` (`id`) ON UPDATE CASCADE 
) ENGINE=InnoDB DEFAULT CHARSET=latin1$$; 

CREATE TABLE `card_types` (
    `id` int(11) NOT NULL, 
    `manufacturer` varchar(45) DEFAULT NULL, 
    `sequance` varchar(32) DEFAULT NULL, 
    `auth_code` varchar(32) DEFAULT NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1$$; 

CREATE TABLE `cards` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `number` int(11) NOT NULL, 
    `type_id` int(11) NOT NULL, 
    `status_id` int(11) NOT NULL, 
    `is_oem` bit(1) NOT NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `number_UNIQUE` (`number`), 
    KEY `cards_type_id_idx` (`type_id`), 
    KEY `cards_status_id_idx` (`status_id`), 
    CONSTRAINT `cards_status_id` FOREIGN KEY (`status_id`) REFERENCES `statuses` (`id`) ON UPDATE CASCADE, 
    CONSTRAINT `cards_type_id` FOREIGN KEY (`type_id`) REFERENCES `card_types` (`id`) ON UPDATE CASCADE 
) ENGINE=InnoDB DEFAULT CHARSET=latin1$$; 

CREATE TABLE `card_assignments` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `door_id` int(11) NOT NULL, 
    `status_id` int(11) NOT NULL, 
    PRIMARY KEY (`id`), 
    KEY `card_assignments_door_id_idx` (`door_id`), 
    KEY `card_assignments_status_id_idx` (`status_id`), 
    CONSTRAINT `card_assignments_door_id` FOREIGN KEY (`door_id`) REFERENCES `doors` (`id`) ON UPDATE CASCADE, 
    CONSTRAINT `card_assignments_status_id` FOREIGN KEY (`status_id`) REFERENCES `statuses` (`id`) ON UPDATE CASCADE 
) ENGINE=InnoDB DEFAULT CHARSET=latin1$$; 

回答

0

我覺得你的建議是完全有效的。請務必爲您的table_name字段選擇一個enum 數據類型;這樣,不同的表名得到 由MySQL透明地映射到整數值。這將使用比VARCHAR字段 更少的內存,並且與特定表相關的選擇錯誤將會更快。額外的 INDEX/KEY超過table_name record_id將進一步提高性能。您可以創建表如下:

CREATE TABLE IF NOT EXISTS `error_logs` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `table_name` enum('sites','tables','doors') CHARACTER SET latin1 COLLATE latin1_general_ci DEFAULT NULL, 
    `record_id` int(11) NOT NULL DEFAULT '0', 
    `error_message` varchar(255) CHARACTER SET latin1 COLLATE latin1_general_ci DEFAULT NULL, 
    `is_active` tinyint(4) NOT NULL DEFAULT '1', 
    PRIMARY KEY (`id`), 
    KEY `table_name` (`table_name`,`record_id`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ; 

選擇由table_name錯誤是那麼容易,因爲:

SELECT * FROM error_logs WHERE table_name = 'sites' 

當添加額外的實體和表格中提到,記得要適當延長table_nameenum

替代,我覺得有些差,你的情況是使用不同的ID字段每個主表:

CREATE TABLE IF NOT EXISTS `error_logs2` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `cards_id` int(11) DEFAULT NULL, 
    `doors_id` int(11) DEFAULT NULL, 
    `sites_id` int(11) DEFAULT NULL, 
    `error_message` varchar(255) CHARACTER SET latin1 COLLATE latin1_general_ci DEFAULT NULL, 
    `is_active` tinyint(4) NOT NULL DEFAULT '1', 
    PRIMARY KEY (`id`), 
    KEY `cards_id` (`cards_id`), 
    KEY `doors_id` (`doors_id`), 
    KEY `sites_id` (`sites_id`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

在這裏,只有ID字段中的一個將包含一個值,而另一個兩個將是NULL。對於插入相關網站表和記錄ID 1的錯誤:

INSERT INTO `error_logs2` (`id`, `cards_id`, `doors_id`, `sites_id`, `error_message`, `is_active`) 
VALUES (NULL, NULL, NULL, '1', 'Exception has occurred: Division by zero.', '1') 

選擇網站的錯誤會的工作如下:

SELECT * FROM error_logs2 WHERE sites_id IS NOT NULL 

但是,爲了能夠涉及錯誤到一個新的實體,您」 d必須在error_logs2表中添加一個新列。但是,爲一個特定實體和id選擇錯誤只需要一個字段比較,例如:

SELECT * FROM error_logs2 WHERE cards_id = 5 
+0

馬塞勒斯,非常感謝您的意見!我將利用您的初始建議並創建表格,如同列表中列出的enum數據類型一樣。謝謝。 – Kate 2013-04-30 21:54:45

+0

不客氣,很高興幫助:) – Marcellus 2013-05-01 14:19:58