更新(根据每个人的回复):
我正在考虑更改我的结构,以便我有一个名为prx_tags_sportsitems的新表。我将完全删除prx_lists。 prx_tags_sportsitems将作为ID表的引用来替换prx_lists.ListString,它曾经存储属于每个prx_sportsitem的标签的ID。
新关系将如此:
prx_tags将包含TagName。这样我仍然可以将每个“标签”维护为一个单独的独特实体。
我查找所有标有“有氧”标签的sportsitems的新查询将类似于以下内容:
SELECT prx_sportsitems.* FROM prx_sportsitems, prx_tags_sportsitems
WHERE prx_tags_sportsitems.OwnerID = prx_sportsitems.ID
AND prx_tags_sportsitems.TagID = (SELECT ID FROM prx_tags WHERE TagName = 'aerobic')
ORDER BY prx_sportsitems.DateAdded DESC LIMIT 0,30;
或许我可以用“IN”条款做点什么,但我还不确定。
在我对脚本进行这么大的修改之前,每个人都赞成吗?评论?非常感谢!
原始帖子:
说到MYSQL查询,我宁愿是新手。当我最初设计我的数据库时,我做了一些相当愚蠢的事情,因为它是我能找到的唯一解决方案。现在我发现它似乎对我的MYSQL服务器造成了太大的压力,因为执行每个查询需要0.2秒,我相信如果它是一个更好的查询可能更像0.02秒(或表设计,如果它来吧!)。我想避免需要重建我的整个网站结构,因为它的设计方式与目前的方式非常相似,所以我希望有更快的mysql查询。
我的数据库中有三个表:
每个体育项目都分配了多个标签名称(类别)。每个“标签”都作为单独的结果存储在prx_tags中。我在prx_sportsitems中的体育项目的prx_lists中创建一个“列表”,并通过链接到prx_sportsitems.ID的prx_lists.OwnerID链接它们
这是我当前的查询(查找所有标记为“有氧”的体育项目):
SELECT prx_sportsitems.*
FROM prx_sportsitems, prx_lists
WHERE prx_lists.ListString LIKE (CONCAT('%',(SELECT prx_tags.ID
FROM prx_tags
WHERE prx_tags.TagName = 'aerobic'
limit 0,1),'#%'))
AND prx_lists.ListType = 'Tags-SportsItems'
AND prx_lists.OwnerID = prx_sportsitems.ID
ORDER BY prx_sportsitems.DateAdded
DESC LIMIT 0,30
为了帮助澄清更多信息,包含所有标记ID的列表位于名为ListString的单个字段中,我将其结构如下:“#1#2#3#4#5”......从中,上面的查询“concats”prx_tags.ID哪个标记名是'有氧'。
我的想法是,可能没有更快的查询存在,我需要简单地接受我需要做一些更简单的事情,例如将所有标签放在列表中,直接放在prx_sportsitems中的一个名为“new”的新字段中TagsList“然后我可以简单地运行一个查询,它可以从prx_sportsitems中选择*,其中TagsList LIKE'%aerobic%' - 但是,我想避免重新设计我的整个网站。我真的后悔没有事先考虑优化:(
答案 0 :(得分:7)
每当我写一个查询,并且认为我需要使用LIKE
时,我脑子里就会发出一个警报,表示可能有更好的设计。这肯定是这种情况。
您需要重新设计prx_lists
表。从你所说的,很难说出确切的架构应该是什么,但这是我最好的猜测:
prx_lists
应该有三列:OwnerID
,ListType
和TagName
。然后,对于OwnerID具有的每个标记,您将拥有一行。您的上述查询现在看起来像这样:
SELECT prx_sportsitems.*
FROM prx_sportsitems, prx_lists
where prx_lists.TagName = 'aerobic'
AND prx_lists.OwnerID = prx_sportsitems.ID
这是一个更有效的查询。也许ListType
也不属于该表,但如果没有关于该列用于什么的更多信息,很难说。
不要忘记create the appropriate indexes!这将提高性能。
重构数据库架构可能会很痛苦,但在我看来,这是解决长期问题的唯一方法。
答案 1 :(得分:1)
为了帮助澄清更多,列表即 包含所有标记ID在里面 一个名为ListString和I的字段 结构它是这样的:“#1#2#3#4#5”......从那里,上面的查询“concats”prx_tags.ID 标记名是'有氧'。
那里有你的问题。不要将分隔数据存储在DB字段(ListString)中。以这种方式建模数据将极难/不可能针对它编写高性能查询。
建议:将ListString的内容分解为相关的表格,每个项目都有一行。
答案 2 :(得分:1)
通过建立理智的表格,你可能会获得至少一个数量级的改善。
我真的后悔没有调查 预先优化
这不是导致你的问题的原因。不了解数据库设计的基础知识会导致您的问题。 (这是一个观察,而不是批评。你可以解决无知。你无法修复愚蠢。)
<强>后来强>:
发布您的existing table structure和您提议的更改。我们能够预测您的代码将会做什么,而不是能够预测您对代码的描述会做什么,您会更高兴。
答案 3 :(得分:1)
包含所有标记ID的列表位于名为ListString的单个字段中,我将其结构如下:“#1#2#3#4#5”......从中,上面的查询“concats “prx_tags.ID这个标记名是'有氧'。
不仅存储非规范化数据,而且分隔符不常见。
改进方法的最快方法是将当前使用的分隔符(“#”)更改为逗号:
UPDATE PRX_LISTS
SET liststring = REPLACE(liststring, '#', ',')
然后,您可以使用MySQL's FIND_IN_SET function:
SELECT si.*
FROM PRX_SPORTSITEMS si
JOIN PRX_LISTS l ON l.ownerid = si.id
JOIN PRX_TAGS t ON FIND_IN_SET(t.id, l.liststring) > 0
WHERE t.tagname = 'aerobic'
AND l.listtype = 'Tags-SportsItems'
ORDER BY si.DateAdded DESC
LIMIT 0, 30
正如您所经历的那样,在非规范化数据中搜索细节效果不佳,并使查询过于复杂。您需要更改PRX_LISTS
表,以便一行包含SPORTSITEM.ownerid
和PRX_TAGS.id
的唯一组合,以及您可能需要的任何其他列。我也建议重命名 - 究竟是什么?这个名字太通用了:
CREATE TABLE SPORTSITEM_TAGS_XREF (
sportsitem_ownerid INT,
tag_id INT,
PRIMARY KEY (sportsitem_ownerid INT, tag_id)
)