2015-05-20 108 views
3

我們正在使用的具有架構像下表: -MYSQL:分區表保留ID唯一

CREATE TABLE `user_subscription` (
`ID` varchar(40) NOT NULL, 
`COL1` varchar(40) NOT NULL, 
`COL2` varchar(30) NOT NULL, 
`COL3` datetime NOT NULL, 
`COL4` datetime NOT NULL, 
`ARCHIVE` tinyint(1) NOT NULL DEFAULT '0', 
PRIMARY KEY (`ID`) 
) 

現在我們想要做的列ARCHIVE分區。 ARCHIVE可以只有2個值0或1,因此2個分區。

其實在我們的案例中,我們使用分區作爲存檔過程。要進行分區,我們需要將ARCHIVE列作爲主鍵的一部分。但是這裏的問題是2行可以具有不同的ID和不同的ARCHIVE列值。事實上,對於我們來說這不是主要問題,因爲2行將在不同的分區中。問題是我們何時將其中一個存檔列值更新爲其他存儲列值,以將其中一個行移動到存檔分區,然後它不會允許我們更新提供「重複錯誤」的條目。

有人可以幫忙嗎?

+0

爲什麼你的'id'會被重複? –

+0

@pala_因爲id和歸檔必須是主鍵組合才能進行分區工作,因此可以針對不同的歸檔列值0和1複製id。 – hatellla

+0

...您仍然可以在id上擁有唯一的索引 –

回答

0

不幸的是,

一個UNIQUE INDEX(或PRIMARY KEY)必須包括表的分區功能

而且由於MySQL中的所有列不支持檢查約束或者,唯一的醜陋的解決方法,我可以想想通過手動強制執行唯一性:觸發器:

CREATE TABLE t (
    id INT NOT NULL, 
    archived TINYINT(1) NOT NULL DEFAULT 0, 
    PRIMARY KEY (id, archived), -- required by MySQL limitation on partitioning 
) 
PARTITION BY LIST(archived) (
    PARTITION pActive VALUES IN (0), 
    PARTITION pArchived VALUES IN (1) 
); 

CREATE TRIGGER tInsert 
BEFORE INSERT ON t FOR EACH ROW 
CALL checkUnique(NEW.id); 

CREATE TRIGGER tUpdate 
BEFORE UPDATE ON t FOR EACH ROW 
CALL checkUnique(NEW.id); 

DELIMITER // 
CREATE PROCEDURE checkUnique(pId INT) 
BEGIN 
    DECLARE flag INT; 
    DECLARE message VARCHAR(50); 
    SELECT id INTO flag FROM t WHERE id = pId; 
    IF flag IS NOT NULL THEN 
    -- the below tries to mimic the error raised 
    -- by a regular UNIQUE constraint violation 
    SET message = CONCAT("Duplicate entry '", pId, "'"); 
    SIGNAL SQLSTATE "23000" SET 
     MYSQL_ERRNO = 1062, 
     MESSAGE_TEXT = message, 
     COLUMN_NAME = "id"; 
    END IF; 
END // 

fiddle

MySQL's limitations on partitioning是這樣一個downer(特別是它缺乏對外鍵的支持),我建議不要使用它,直到表增長得如此之大,以至於成爲一個實際的關注。