2011-09-14 28 views
0

我需要這個實現:MySQL大表管理?

enter image description here

我使用PHP和MySQL。正如你所看到的價格可以動態構建。爲了管理這個要求我做了以下模式:

`tbl_states` (id, state) 
`tbl_prices` (id, price) 
`tbl_years` (id, year) 
`tbl_states_prices` (id, state_id, customer_id, year_id, price_id, value) 

每個價格的值將被存儲在tbl_states_prices。價值取決於國家,客戶和年份。我擔心這個表的大小,因爲最大年數是20,價格大約是6,平均客戶數是300.

我不知道使用這種模式會帶來什麼後果。我應該如何管理這張桌子?拆分成每個客戶的小桌子?看法?我對數據庫缺乏經驗並不能幫助我。建議將不勝感激。

+0

感謝stereofrog,甚至當桌子每週都會增長? – ivantxo

回答

1

您提供的信息很少,所以我必須再次猜測我自己的場景 ,這是可能的。

我們爲零售商提供信息。每個零售商都有很多客戶,並且一個客戶可能成爲許多零售商的客戶,所以這種關係需要多對多的關係,這需要另一個表來提供幫助。

對於每一位零售商和零售商,我們都保持獨特的收費(預測)。 一次收費只屬於一位顧客。

Year1,year2字段否,年份必須是單個字段中沒有多少字段。和 ,因爲這是一個有多個出現的字段(類似於電話的情況下) 好的做法需要其他表來幫助我們。所以沒有像 動態字段這樣的東西,字段是靜態的像石頭一樣的基礎規則!另外,如果我們在談論真正龐大的數據(我不認爲是這種情況,我們可能會打破 與特定年份相關的部分的收費表,例如 需要更多工作)。
一個非常重要的事情..你可能有一個特定的方式在你的腦海裏你將如何 呈現水平,垂直這個數據,第1年,第2年等..但是你永遠不會 讓這個想法干擾你的關係圖,視覺顯示(可隨時改變) 和er設計必須保持分開。

至於美國有一個小竅門,以保持田間小,這意味着更快的工作 和省略狀態table.It需要一個簡單的PHP函數,給定的狀態 例如,加利福尼亞州,當它存儲TINYINT而不是varchar加州。或者你可以保留一個 狀態表,其tinyint id作爲外鍵傳遞給收費表。 選擇你喜歡的任何一個。

/實體是零售商和客戶的推廣。一般化 需要處理類似的領域,例如零售商和客戶 有電子郵件,地址等。另一方面,客戶和零售商是 我們需要它來處理不同領域的實體的規範 例如我們不在乎一個退休者是否已婚!/

以下僅爲示例。

drop table if exists `Entity_Phone`; 
drop table if exists `Retailer_Customer`; 
drop table if exists `Charge`; 
drop table if exists `Retailer`; 
drop table if exists `Customer`; 

drop table if exists `Entity`; 
    CREATE TABLE `Entity` (
    `entity_id` INT UNSIGNED NOT NULL AUTO_INCREMENT, 
    /*example code 0 is for retailer and code 1 is for customer*/ 
    `entity_code` tinyint not null, 
    `entity_other_field` VARCHAR(30) NOT NULL, 
    PRIMARY KEY (`entity_id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT; 
/*You don't have to use utf8 if not needed*/ 

/*Phone number, instead of only phone you can store more info 
like multiple emails etc, just change the table name to make sense, 
the datatype and in the php function that associates codes add 
as many codes needed*/ 
CREATE TABLE `Entity_Phone` (
    `entity_id` INT UNSIGNED NOT NULL , 
    `phone` BIGINT UNSIGNED NOT NULL , 
    /*code 1 is for fix phone, 2 is for mobile phone and 3 for fax*/ 
    `identification_code` TINYINT UNSIGNED DEFAULT '1' NOT NULL, 
    PRIMARY KEY (`entity_id`), 
    CONSTRAINT `fk1EntData` FOREIGN KEY (`entity_id`) 
     REFERENCES `Entity` (`entity_id`) 
     ON DELETE CASCADE 
) ENGINE=InnoDB ROW_FORMAT=COMPACT; 


    CREATE TABLE `Retailer` ( 
    `retailer_fname` VARCHAR(30) NOT NULL, 
    `retailer_lname` VARCHAR(30) NOT NULL, 
    /*pkey directly shared from entity table, just with a different name*/ 
    `retailer_id` INT UNSIGNED NOT NULL , 
    PRIMARY KEY (`retailer_id`), 
    CONSTRAINT `fk1RetEnt` FOREIGN KEY (`retailer_id`) 
     REFERENCES `Entity` (`entity_id`) 
     ON DELETE CASCADE 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT; 

    CREATE TABLE `Customer` ( 
    `customer_fname` VARCHAR(30) NOT NULL, 
    `children_number` tinyint not null, 
    `customer_id` INT UNSIGNED NOT NULL , 
    PRIMARY KEY (`customer_id`), 
    CONSTRAINT `fk1CustData` FOREIGN KEY (`customer_id`) 
     REFERENCES `Entity` (`entity_id`) 
     ON DELETE CASCADE 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT; 



CREATE TABLE `Retailer_Customer` ( 
    `customer_id` INT UNSIGNED NOT NULL , 
    `retailer_id` INT UNSIGNED NOT NULL , 
    PRIMARY KEY (`customer_id`,`retailer_id`), 
    CONSTRAINT `fk1RetCust` FOREIGN KEY (`customer_id`) 
     REFERENCES `Entity` (`entity_id`) 
     ON DELETE CASCADE, 
CONSTRAINT `fk2RetCust` FOREIGN KEY (`retailer_id`) 
     REFERENCES `Entity` (`entity_id`) 
     ON DELETE CASCADE 

) ENGINE=InnoDB ROW_FORMAT=COMPACT; 




/* 
if you want to keep the state table... for example you might need to store 
information for states so you need this table to keep those fields 
CREATE TABLE `State` (
    `state_id` tinyINT UNSIGNED NOT NULL , 
    `state_name` varchar(50) not null , 
    PRIMARY KEY (`state_id`), 
    unique(`state_name`) 
) ENGINE=InnoDB ROW_FORMAT=COMPACT; 
*/ 
CREATE TABLE `Charge` ( 
    `retailer_id` INT UNSIGNED NOT NULL , 
    `customer_id` INT UNSIGNED NOT NULL , 
    `state_code` TINYINT UNSIGNED NOT NULL , 
    /*state could be stored here directly as 
    varchar however this way it asks less space, 
    is faster and allows no orthographical erros 
on insertion */ 
    /*`state_id` tinyint UNSIGNED NOT NULL , if you want the state table*/ 
    `charge_date_time` DATETIME NOT NULL, 
    index(`customer_id`), 
    PRIMARY KEY (`retailer_id`,`customer_id`,`charge_date_time`), 
    CONSTRAINT `fk1Charge` FOREIGN KEY (`retailer_id`) 
     REFERENCES `Retailer` (`retailer_id`) 
     ON DELETE CASCADE, 
    CONSTRAINT `fk2Charge` FOREIGN KEY (`customer_id`) 
     REFERENCES `Customer` (`customer_id`) 
     ON DELETE CASCADE 
/* if you want the state table 
,CONSTRAINT `fk2pr` FOREIGN KEY (`state_id`) 
     REFERENCES `State` (`state_id`) 
     ON DELETE CASCADE 
*/ 
) ENGINE=InnoDB ROW_FORMAT=COMPACT; 



/*This is how you insert a Retailer*/ 
insert into `Entity` (`entity_code`, `entity_other_field`) 
    values ('0','test'); 
insert into `Retailer` (`retailer_fname`, `retailer_lname`, 
    `retailer_id`) values ('John', 'Smith',(SELECT LAST_INSERT_ID())); 
insert into `Entity_Phone` (`entity_id`, `phone`,`identification_code`) values 
((SELECT LAST_INSERT_ID()), 123222,3); 
/****************************************************/ 


/*This is how you insert a Customer*/ 
insert into `Entity` (`entity_code`, `entity_other_field`) 
    values ('1','test'); 
insert into `Customer` (`customer_fname`, `children_number`, 
    `customer_id`) values ('Jimm', 3,(SELECT LAST_INSERT_ID())); 
insert into `Entity_Phone` (`entity_id`, `phone`,`identification_code`) values 
((SELECT LAST_INSERT_ID()), 43543,3); 
/****************************************************/ 




/*This is how you insert a charge*/ 
insert into `Charge` (`retailer_id`, `customer_id`,`state_code`, 
`charge_date_time`) 
    values ((select `retailer_id` from `Retailer` where `retailer_fname`='John'), 
    (select `customer_id` from `Customer` where `customer_fname`='Jimm'),34,(now())); 

    /*This is how you retrieve a charge*/ 
    select * from `Charge` where year(`charge_date_time`) ='2011' 
+0

感謝您的建議和時間。你的回答非常有幫助。我需要更多地瞭解數據庫和編程語言。 – ivantxo

+0

歡迎您!我一直在那裏,理論是必需的,但還不夠,它與實際例子的結合是最好的。也只研究立即感興趣的主題是推薦和更好的原因數據庫理論相當大,涵蓋很多領域。再見! – Melsi

0

如果您需要建議,我建議您在表上使用MyISAM引擎,因爲選擇的速度很快。我在具有+1百萬行的表上使用InnoDB,因爲我需要使用外鍵約束,所以對於mysql來說什麼都沒有。

+0

我會看看MyISAM。我沒有合作過,但我會檢查它。謝謝。 – ivantxo

+1

你剛剛給了他錯誤的建議。當數據集較小時,MyISAM可以更好地工作。除了日誌以外,MyISAM可能是現今在MySQL中存儲任何內容的最糟糕的選擇。正確配置的InnoDB具有穩定的縮放率,MyISAM迅速惡化。 –

0
  1. 第1步=需求分析(與有知識的人一分析討論) 您識別實體(簡單地說,名詞通常是實體:個人,客戶,供應商等和動詞通常是關係:作品,購買,用品等) 所以是一個實體的價格(懷疑),是零售商(我敢打賭)等零售商可能是一個實體,因爲它可以獨立存在,而電話號碼不能獨立存在,電話數字是沒有意義的,除非與一個人有關!顧客可以獨立存在,這很有道理!

  2. 的其他事情(以及許多許多其他的)是問你自己,我要問的數據庫,

    • 我就要求價格與國家只,或國家和年份只有等

我要在這裏停止理論的原因是過於龐大,而且因爲理論是沒有太大的幫助,我會做一些非常實用的通知:

免責聲明

請記住,我不知道需求分析的,所以我可能是tottaly錯了地方

  • 具有表示實體主表(這樣的表是那些沒有外鍵)關於價格(你定義它的方式)可能是一種不好的做法,它可能會損害你的工作。這意味着不一致性,有一個不好的設計,一個非有效的一個等是可以容忍的,不一致性不是。價格和價值......我非常肯定,沒有像價值這樣的東西,只有價格!所以設計說價格1,價格2等我相信是不是要走的路,如果我們正在談論的數據庫表。

    • 有一張桌子多年,沒辦法!年份是一個領域,是一個實體的屬性,而不是一個實體!

    • 國家,你是什麼意思像紐約等,有時它是一個領域。

  • 一個精心設計的表得到了一個主鍵一個簡單的(例如,客戶ID)或複合一個(例如學生ID和過程ID)。在tbl_states_prices第一個字段包含一個ID,我很漂亮這個ID不僅是無用的,而且也有誤導性,也許有害。也許你這樣做是因爲一些外鍵可能是空的,這意味着糟糕的設計。

個不錯的系統要求和設計可能是這樣的:

  1. 我們所保存的零售商信息,所以零售商是一個像名稱,位置,網站,州(紐約),手機領域的實體(通常存儲在第二個表中,原因是具有多次出現的值)等等。從屏幕上看,您將零售商稱爲客戶。

tbl_retailer(retail_id,名字,姓氏等)

  1. 然後你有一個複合主鍵的依賴(與外鍵)表。現在你必須決定日期的詳細程度。如果一年有很多價格,你不能談論年,你必須談論月,周,甚至小時,這一切都取決於價格變化的頻率。

tbl_prices(retail_id,statedatetime

各個領域做出一個複合主鍵!這樣你就不可能有不一致的記錄。在你的設計中,我可以爲同一個客戶輸入相同的價格,同樣的狀態一百萬次,唯一的區別是一個沒有意義的id(tbl_states_prices的第一個字段)。它就像插入一百萬次 1.約翰·史密斯的父親結婚等 2.約翰·史密斯的父親結婚等 .... 1000000約翰·史密斯的父親結婚等

如何保持一致,有效等是這個?

我刪除了這個answear的一小部分,它在一個新的answear中被覆蓋和改進。

+0

非常感謝!我正在檢查我的設計。 – ivantxo

+0

謝謝。這是零售商的電費預測(不是價格,對不起!)。這些值由管理員在我設計的網格或矩陣中手動輸入(可能不明顯)。因此,我寧願使用另一個表格,我將這些值存儲在特定的用戶預測(customer_id,charge_id,year1,year2,...)中。但是,每個客戶的年數都會發生變化。我如何使用動態列管理表? – ivantxo