优化MySQL搜索过程

时间:2009-02-12 11:05:16

标签: php mysql search methods

以下是方案1。

我有一个名为“items”的表,表中有2列,e。 G。 item_iditem_name。 我以这种方式存储我的数据:     item_id | ITEM_NAME

Ss001   | Shirt1
Sb002   | Shirt2
Tb001   | TShirt1
Tm002   | TShirt2

...等,我这样存储: 第一个字母是衣服的代码,即S代表衬衫,T代表T恤 第二个字母是大小,即s代表小,m代表中等,b代表大 让我们在我的项目表中说我有10,000件物品。我想做快速检索,假设我想找一件特定的衬衫,我可以使用:

方法一:

SELECT * from items WHERE item_id LIKE Sb99; 

或者我应该这样做:

方法2:

SELECT * from items WHERE item_id LIKE S*; 

*存储结果,然后执行第二次搜索大小,然后第三次搜索id。像哈希表概念。 我想要实现的是,我想通过首先搜索衣服代码,然后按照大小代码然后是id代码来搜索所有数据,而不是搜索所有数据。在mysql中哪一个在速度方面更好。从长远来看哪一个更好。我想减少流量而不是经常打扰数据库。

感谢大家解决我的第一个场景。但另一种情况出现了:

情景2:

我正在使用PHP和MySQL。继续从早期的故事。如果我的用户表结构是这样的:

user_id | username | items_collected

U0001   | Alex     | Ss001;Tm002
U0002   | Daniel   | Tb001;Sb002
U0003   | Michael  | ...
U0004   | Thomas   | ...

我将items_collected存储在id格式中,因为有一天每个用户最多可以收集数百个项目,如果我存储为字符串,即Shirt1,pants2,......,则需要非常大量的数据库空间(想象一下)我们有1000个用户,有些项目名称很长。)

如果以id格式存储,维护会更容易吗?

如果我们说,我想显示图像,图像的名称是项目的名称+ jpg。怎么做?它是这样的:

$ result =从userid = $ userid

的用户中选择items_collected

使用php explode:

$ itemsCollected = explode($ result,“;”);

之后,匹配items表中的每个项目,所以它希望:

shirt1,pants2等

使用循环功能,循环每个值并添加“.jpg”以显示图像?

5 个答案:

答案 0 :(得分:3)

第一种方法会更快 - 但IMO并不是正确的做法。我同意tehvan的意见。

我建议保持item_id不变,但是为代码添加一个额外的字段,为大小添加一个,然后你可以这样做:

select * from items where item_code = 'S' and item_size = 'm' 

使用索引可以大大提高性能,并且您可以轻松匹配各种尺寸或代码。

select * from items where item_code = 'S' and item_size IN ('m','s')

按如下方式迁移数据库:

alter table items add column item_code varchar(1) default '';
alter table items add column item_size varchar(1) default '';

update items set item_code = SUBSTRING(item_id, 1, 1);
update items set item_size = SUBSTRING(item_id, 2, 1);

对代码的更改应该同样易于添加。长期利益将是值得的。


对于方案2 - 这不是从数据库存储和检索数据的有效方法。当以这种方式使用时,数据库仅充当存储引擎,通过将多个数据编码到字段中,从而阻止数据库的关系部分变得有用。

在这种情况下你应该做的是另一张桌子,称之为'items_collected'。架构将沿着

的方向
CREATE TABLE items_collected (
   id int(11) NOT NULL auto_increment KEY,
   userid int(11) NOT NULL,
   item_code varchar(10) NOT NULL,  
   FOREIGN KEY (`userid`) REFERENCES `user`(`id`),
   FOREIGN KEY (`itemcode`) REFERENCES `items`(`item_code`)
 );

外键确保有Referential integrity,这是必不可少的to have referential integrity

然后,对于您给出的示例,您将拥有多条记录。

 user_id | username | items_collected
 U0001   | Alex     | Ss001
 U0001   | Alex     | Tm002
 U0002   | Daniel   | Sb002
 U0002   | Daniel   | Tb001
 U0003   | Michael  | ...
 U0004   | Thomas   | ...

答案 1 :(得分:1)

第一个优化是将id分成三个不同的字段: 一个用于类型,一个用于大小,一个用于当前id结尾(无论结束意味着什么) 如果您真的想保留当前结构,请立即查看结果(选项1)。

答案 2 :(得分:1)

如果您想加快结果速度,您应该将列拆分为多个列,每个属性对应一列。

第2步是为每列创建索引。请记住,mysql每个查询每个表只使用一个索引。因此,如果您真的想要快速查询,并且您的查询对这些属性的影响很大,那么您可能希望在(类型,大小,结尾),(类型,结尾,大小)等上创建索引。

例如使用

的查询
select * from items where type = s and size = s and ending = 001

可以从索引(类型,大小,结尾)中受益,但是:

select * from items where  size = s and ending = 001

不能,因为索引只会按顺序使用,所以它需要类型,然后是大小,然后结束。如果您真的想要快速搜索,这就是您可能需要多个索引的原因。

另一个注意事项,通常在查询中使用*不是一个好主意,而是只选择您需要的列。

答案 3 :(得分:1)

modelsizeid需要有三列,并以这种方式对其进行索引:

CREATE INDEX ix_1 ON (model, size, id)
CREATE INDEX ix_2 ON (size, id)
CREATE INDEX ix_3 ON (id, model)

然后,您将能够有效地搜索任何参数子集:

  • model-size-idmodel-sizemodel查询将使用ix_1;
  • size-idsize查询将使用ix_2;
  • model-idid查询将使用ix_3

列上的索引现在等同于ix_1,您可以使用此索引有效搜索适当的条件(model-size-idmodel-size和{{1} })。

实际上,有一个名为model的访问路径可用于搜索复合索引的非第一列,但INDEX SKIN SCAN不支持它AFAIK。


如果您需要坚持当前的设计,则需要索引字段并使用以下查询:

MySQL

所有这些查询都将使用索引(如果有)。

无需插入多个查询。

答案 4 :(得分:0)

我很高兴您将item_id设计为可以通过“Starts with”测试进行搜索。索引将为您快速解决。

我不知道MySQL,但是在MSSQL上有一个“大小”列的索引只有S,M,L的选择最有可能无法实现任何东西,索引将不会被使用,因为值它包含的选择性不够 - 即更快地遍历所有数据而不是“在索引中查找第一个S条目,现在检索该行的数据页面......”

异常是索引覆盖查询的地方 - 即WHERE子句的几个部分(实际上,所有这些部分以及SELECT列)都包含在索引中。但是,在这种情况下,索引中的第一个字段(在MSSQL中)需要是选择性的。因此,在索引中首先放置具有最不同值的列。

如果您的应用程序有大小,颜色等的选项列表,您应该将这些数据属性放在记录中的单独列中 - 并将单独的表与所有可用颜色和大小的列表相对应,然后您可以验证给予产品的颜色/尺寸实际上是在颜色/尺寸表中定义的。减少垃圾进/出垃圾问题!

您的item_selected需要位于单独的表中,以便“标准化”。不要将分隔列表存储在单个列中,使用单独的表将其存储在单独的表中

因此,您的USERS表将包含user_id&用户名

您的新的items_collected表将包含user_id& item_id(可能还包括购买日期或发票编号)

然后你可以说“Alex买了什么”(你的设计有那个)以及“谁买了Ss001”(在你的设计中,需要翻阅USERS表中的所有行并将items_collected分割为找出哪些包含Ss001 [1])

[1]请注意,使用LIKE实际上并不安全,因为你可能有一个“Ss001XXX”的item_id,它匹配WHERE items_collected LIKE'%Ss001%'