![](/img/trans.png)
[英]MySQL database design, two types of records - use one table or two separate tables?
[英]Basic SQL design question: One table with lots of repeated text, or two separate tables?
一個通用的數據庫設計問題:
假設我正在組合一個相當大的數據庫 - 比如說有數萬行,而不是很多列 - 我希望其中一列是一個識別“標簽”,最明顯的是一個 30-50 的長字符串人物。
並且不同標簽的數量將相當有限。
我讀過的關於 SQL 和數據庫設計的每一篇介紹性文章都表明,您應該小心為您的信息選擇正確的數據類型 - 如果您可以通過將其存儲為 integer 來獲得信息,請不要將其存儲為浮點數,不要如果您可以將信息存儲為數字,則將其存儲為文本 - 以防止您的數據庫變得不必要的大。 但我不確定這對性能有多大影響。
在我的特殊情況下,創建第二個表似乎很容易,我的所有英文“標簽”與一些任意的 integer “代碼”配對。 然后,我可以在我的主表中只存儲 integer 代碼,使其更小。 但是,然后,對於用戶從主表訪問他們想要的數據 - 在不知道 integer 代碼並且只知道英文標簽的情況下 - 每個查詢(我認為)必須看起來像:
"SELECT * FROM maintable WHERE code = (SELECT code FROM secondtable WHERE tag = 'English tag')"
這似乎可行,但是每個查詢實際上都是兩個查詢。
那么,通過將英文“標簽”替換為 integer“代碼”來縮小主表是否可能會帶來有意義的性能優勢? 而且,如果是這樣,這種性能改進是否可能超過將查詢數量翻倍的性能成本?
在這個問題上有經驗法則嗎? 一般首選的處理方式? 如果是這樣,我很想在走得太遠之前知道。
在我看來,就維護和可擴展性而言,最好有兩個帶有索引值的單獨表,因此您將有一個 TAG 表,每個表都有索引 ID,而主表僅引用這些 ID。 正如在這個問題中指出的那樣,最好使用 JOIN 來獲取這兩個值,所以你會做這樣的事情:
SELECT
*
FROM maintable m
JOIN tagtable t ON t.id = m.tag //You can choose also LEFT JOIN
WHERE
m.tag='english tag'
但最后,這一切都取決於您的具體需求。
讓我們舉一個具體的例子。 問題是考慮兩種方法:
Take1 :只有一個表,直接嵌入(和復制) tag
字符串,類似於:
CREATE TABLE take1 (
id INTEGER NOT NULL PRIMARY KEY,
tag TEXT,
foo1 INTEGER,
foo2 INTEGER
);
Take2 :兩個表,其中主表通過 ID 引用tag
字符串,類似於:
CREATE TABLE take2 (
id INTEGER NOT NULL PRIMARY KEY,
tag_id INTEGER,
foo1 INTEGER,
foo2 INTEGER
);
CREATE TABLE tags (
tag_id INTEGER NOT NULL PRIMARY KEY,
tag TEXT
);
第一條評論: take1使用了一個未標准化的表。 例如,假設您決定編輯其中一個標簽(例如拼寫錯誤)。 使用take1 ,您必須編輯嵌入給定標簽的所有行。 使用take2 ,您只需編輯 1 行。
我用 SQLite 寫了一個小程序來比較兩種方法的性能,假設主表有 80K 行,唯一標簽為 38。
從文件大小的角度來看:
從性能上看:
對於take1查詢
select count(*)
from take1
where tag = "consciousness as a paradox.";
需要 8ms
對於take2查詢
select count(*)
from take2, tags
where take2.tag_id = tags.tag_id and
tags.tag = "consciousness as a paradox.";
需要 10 毫秒
但是,想一想,我們也可以寫
select count(*)
from take2
where take2.tag_id = (
select tag_id from tags where tag = "consciousness as a paradox."
);
而這個需要 5ms。
因此,根據這些微基准, take2不僅從設計角度來看更好,而且從性能角度來看(至少執行上述查詢)。
最后一點:我寫了一個程序,因為我還需要填寫表格,但是如果已經有表格可用,也可以直接使用 sqlite shell 和.timer on
來獲取時序信息:
$ sqlite3 take2.db
SQLite version 3.28.0 2019-04-15 14:49:49
sqlite> .timer on
sqlite> select count(*)
...> from take2
...> where take2.tag_id = (
...> select tag_id from tags where tag = "consciousness as a paradox."
...> );
2105
Run Time: real 0.005 user 0.004756 sys 0.000089
(2105來自80K/38)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.