插入 MySQL 中的 tag_map
INSERTing into a tag_map in MySQL
我有一篇简单的文章和 tag_map 个表格
CREATE TABLE Articles
(
ArticleID int(11) unsigned NOT NULL AUTO_INCREMENT,
Title varchar(255),
PRIMARY KEY(ArticleID)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_general_ci
CREATE TABLE Tags
(
TagID int(11) unsigned NOT NULL AUTO_INCREMENT,
Tag varchar(255),
UNIQUE INDEX(Tag),
PRIMARY KEY(TagID)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_general_ci
CREATE TABLE TagMap
(
ArticleID int(11) unsigned NOT NULL,
TagID int(11) unsigned NOT NULL,
INDEX(TagID),
PRIMARY KEY(ArticleID,TagID)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_general_ci
我通过PHP
添加标签
$result = $mysqli->query("SELECT TagID FROM Tags WHERE Tag='$tag'");
if($result->num_rows == 1) {
$row = $result->fetch_assoc();
$tag_id = $row['TagID'];
}
else {
$mysqli->query("INSERT INTO Tags (Tag) VALUES ('$tag')");
$tag_id = $mysqli->insert_id;
}
$mysqli->query("INSERT INTO TagMap (ArticleID,TagID) VALUES ($article_id,$tag_id)");
我想知道在 MySQL.[=17= 的一个查询中是否有更快的方法来执行此操作]
在这里,我需要 2 或 3 个查询来添加每个标签。
此外,当我们有一个标签列表
时,我希望找到一种批量处理 INSERT
的方法(可能通过 LOAD DATA LOCAL INFILE
)
ArticleID,Tag
1,tag2
2,tag11
4,tag3
一个模式:
CREATE PROCEDURE load_to_TagMap ()
BEGIN
-- create table for loading data
CREATE TABLE tmp_TagMap ( ArticleID INT, Tag VARCHAR(255) ) ENGINE = Memory;
-- load data from file
LOAD DATA INFILE '/directory/filename.ext'
INTO TABLE tmp_TagMap
SKIP 1 LINES;
-- add absent tags into Tags table
INSERT INTO Tags (Tag)
SELECT tmp_TagMap.Tag
FROM tmp_TagMap
LEFT JOIN Tags USING (Tag)
WHERE Tags.Tag IS NULL;
-- insert loaded data into TagMap table with lookup
INSERT INTO TagMap
SELECT ArticleID, TagID
FROM Tag
JOIN tmp_TagMap USING (Tag);
-- remove loaded data table
DROP TABLE tmp_TagMap;
END
从 PHP 只需执行 CALL load_to_TagMap;
.
过度规范化。
“标签”往往是短字符串,对吗?为每个创建一个 INT
并进行二次查找的开销是不值得的。将 Tags
和 TagMap
替换为
CREATE TABLE Tags
(
ArticleID int(11) unsigned NOT NULL,
Tag VARCHAR(255) NOT NULL,
PRIMARY KEY(ArticleID,Tag)
INDEX(Tag, ArticleID)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_general_ci
这可能是有趣的:http://mysql.rjweb.org/doc.php/lists
更多
SELECT COUNT(*) FROM Tags WHERE Tag = '...';
非常有效,即使 Tag 为 VARCHAR
。这也简化了您的代码——您不需要额外的代码来触发计数器;删除文章时也很容易减少计数器:
DELETE FROM Tags WHERE ArticleID = ...;
如果您希望每个标签有 10 万篇文章,则可能存在性能问题。您期望有多少篇文章和标签?
如果大图是“显示标签='...'的 'latest' 10 篇文章,那么性能问题将出现在 ORDER BY date DESC LIMIT 10
。目前这涉及到一个连接到文章 table、检查是否 'deleted'、排序等。但我有一个解决方案:http://mysql.rjweb.org/doc.php/lists
我有一篇简单的文章和 tag_map 个表格
CREATE TABLE Articles
(
ArticleID int(11) unsigned NOT NULL AUTO_INCREMENT,
Title varchar(255),
PRIMARY KEY(ArticleID)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_general_ci
CREATE TABLE Tags
(
TagID int(11) unsigned NOT NULL AUTO_INCREMENT,
Tag varchar(255),
UNIQUE INDEX(Tag),
PRIMARY KEY(TagID)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_general_ci
CREATE TABLE TagMap
(
ArticleID int(11) unsigned NOT NULL,
TagID int(11) unsigned NOT NULL,
INDEX(TagID),
PRIMARY KEY(ArticleID,TagID)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_general_ci
我通过PHP
添加标签$result = $mysqli->query("SELECT TagID FROM Tags WHERE Tag='$tag'");
if($result->num_rows == 1) {
$row = $result->fetch_assoc();
$tag_id = $row['TagID'];
}
else {
$mysqli->query("INSERT INTO Tags (Tag) VALUES ('$tag')");
$tag_id = $mysqli->insert_id;
}
$mysqli->query("INSERT INTO TagMap (ArticleID,TagID) VALUES ($article_id,$tag_id)");
我想知道在 MySQL.[=17= 的一个查询中是否有更快的方法来执行此操作]
在这里,我需要 2 或 3 个查询来添加每个标签。
此外,当我们有一个标签列表
时,我希望找到一种批量处理INSERT
的方法(可能通过 LOAD DATA LOCAL INFILE
)
ArticleID,Tag
1,tag2
2,tag11
4,tag3
一个模式:
CREATE PROCEDURE load_to_TagMap ()
BEGIN
-- create table for loading data
CREATE TABLE tmp_TagMap ( ArticleID INT, Tag VARCHAR(255) ) ENGINE = Memory;
-- load data from file
LOAD DATA INFILE '/directory/filename.ext'
INTO TABLE tmp_TagMap
SKIP 1 LINES;
-- add absent tags into Tags table
INSERT INTO Tags (Tag)
SELECT tmp_TagMap.Tag
FROM tmp_TagMap
LEFT JOIN Tags USING (Tag)
WHERE Tags.Tag IS NULL;
-- insert loaded data into TagMap table with lookup
INSERT INTO TagMap
SELECT ArticleID, TagID
FROM Tag
JOIN tmp_TagMap USING (Tag);
-- remove loaded data table
DROP TABLE tmp_TagMap;
END
从 PHP 只需执行 CALL load_to_TagMap;
.
过度规范化。
“标签”往往是短字符串,对吗?为每个创建一个 INT
并进行二次查找的开销是不值得的。将 Tags
和 TagMap
替换为
CREATE TABLE Tags
(
ArticleID int(11) unsigned NOT NULL,
Tag VARCHAR(255) NOT NULL,
PRIMARY KEY(ArticleID,Tag)
INDEX(Tag, ArticleID)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_general_ci
这可能是有趣的:http://mysql.rjweb.org/doc.php/lists
更多
SELECT COUNT(*) FROM Tags WHERE Tag = '...';
非常有效,即使 Tag 为 VARCHAR
。这也简化了您的代码——您不需要额外的代码来触发计数器;删除文章时也很容易减少计数器:
DELETE FROM Tags WHERE ArticleID = ...;
如果您希望每个标签有 10 万篇文章,则可能存在性能问题。您期望有多少篇文章和标签?
如果大图是“显示标签='...'的 'latest' 10 篇文章,那么性能问题将出现在 ORDER BY date DESC LIMIT 10
。目前这涉及到一个连接到文章 table、检查是否 'deleted'、排序等。但我有一个解决方案:http://mysql.rjweb.org/doc.php/lists