Php 以最佳方式从数据库中按属性搜索产品

Php 以最佳方式从数据库中按属性搜索产品,php,mysql,search,entity-attribute-value,Php,Mysql,Search,Entity Attribute Value,我想找到一种从数据库中按属性搜索产品的有效方法,数据库中的数据是按属性组织的 共有两个表格: 产品,存储产品,具有产品id ProductAttribute—产品的属性值 SQL: 不同的产品可以有不同数量的属性。例如。产品“t恤”有大小和颜色,产品“笔记本”是否有cpu和ram。一个产品可以有10个以上的属性 我想为产品创建一个搜索页面,让用户从过滤器中选择值,为当前产品类型命名 我的问题是,从这些表进行搜索的MySQL查询效率低下。按10个产品属性搜索需要10个与ProductAttri

我想找到一种从数据库中按属性搜索产品的有效方法,数据库中的数据是按属性组织的

共有两个表格:

  • 产品,存储产品,具有产品id
  • ProductAttribute—产品的属性值
SQL:

不同的产品可以有不同数量的属性。例如。产品“t恤”有大小和颜色,产品“笔记本”是否有cpu和ram。一个产品可以有10个以上的属性

我想为产品创建一个搜索页面,让用户从过滤器中选择值,为当前产品类型命名

我的问题是,从这些表进行搜索的MySQL查询效率低下。按10个产品属性搜索需要10个与ProductAttribute表的联接:

SELECT P.id
FROM Product P
JOIN ProductAttribute A1 ON (P.id = A1.product_id AND A1.attribute = 'cpu' AND A1.value = 'xxx')
JOIN ProductAttribute A2 ON (P.id = A2.product_id AND A2.attribute = 'ram' AND A2.value = 'yyy')
JOIN ProductAttribute A3 ON (P.id = A3.product_id AND A3.attribute = 'hdd' AND A3.value = 'zzz')
# ... more attributes require more joins
我可以想象我该如何解决这个问题:我可以为每个attibute集合创建索引表(一个用于笔记本电脑的表,另一个用于t恤衫的表等等),并根据产品属性的变化重新生成这些索引表

但我想知道是否有现有的解决方案,也许一些搜索引擎可以做这项工作

我使用PHP/MySQL,但我并不局限于此-任何解决方案都会很有趣

更新:(扰流板:我仍然对是否存在用于此任务的搜索引擎/索引器感兴趣)我为具有多个连接的查询和按索引表查询创建了比较测试。索引表是一个所有属性都是独立列的表。结果:联接-4.5s,索引表-0.2s

带有联接的查询示例:

SELECT P.id FROM Product P
JOIN ProductAttribute color ON (P.id = color.product_id AND color.attribute_id = 17 AND color.int_value IN (152,146,101,152,118,109))
JOIN ProductAttribute size ON (P.id = size.product_id AND size.attribute_id = 34 AND size.int_value IN (288,210,246,275,258,289))
JOIN ProductAttribute brand ON (P.id = brand.product_id AND brand.attribute_id = 51 AND brand.int_value IN (305,303,300,375,308,340))
JOIN ProductAttribute material ON (P.id = material.product_id AND material.attribute_id = 68 AND material.int_value IN (426,463,465,459,418,460))
JOIN ProductAttribute length ON (P.id = length.product_id AND length.attribute_id = 85 AND length.float_value > 10 AND length.float_value < 49)
JOIN ProductAttribute height ON (P.id = height.product_id AND height.attribute_id = 102 AND height.float_value > 78 AND height.float_value < 186)
JOIN ProductAttribute weight ON (P.id = weight.product_id AND weight.attribute_id = 119 AND weight.float_value > 10 AND weight.float_value < 15)
JOIN ProductAttribute waterproof ON (P.id = waterproof.product_id AND waterproof.attribute_id = 136 AND waterproof.bool_value = 1)
JOIN ProductAttribute tags ON (P.id = tags.product_id AND tags.attribute_id = 153 AND tags.string_value LIKE '%alluring%')
;

因此,在这种情况下,我可以看到索引表比连接更有效。我想知道是否有任何解决方案可以帮助生成(并保持在实际状态)这样的索引表,或者提供一些其他方法来快速搜索具有多个属性的产品。

正确地实现搜索非常困难,您将在这一过程中重新发明许多轮子。如果可以的话,我建议您使用类似的东西,它很容易使用,而且从长远来看,它需要多次连接。对于>10k的产品,速度很慢。@对不起,我添加了更新信息。正在运行测试。您还在平移吗?关于发展?您希望在attributes表上处理多少行?这将有助于提供更好的建议。我认为在采用EAV模型时,一个有用的想法是根据值数据类型将实体分离出来。因此,您将有一个日期类型值表、一个整数值表、一个十进制类型的表和一个varchar类型的表。
SELECT P.id FROM Product P
JOIN ProductAttribute color ON (P.id = color.product_id AND color.attribute_id = 17 AND color.int_value IN (152,146,101,152,118,109))
JOIN ProductAttribute size ON (P.id = size.product_id AND size.attribute_id = 34 AND size.int_value IN (288,210,246,275,258,289))
JOIN ProductAttribute brand ON (P.id = brand.product_id AND brand.attribute_id = 51 AND brand.int_value IN (305,303,300,375,308,340))
JOIN ProductAttribute material ON (P.id = material.product_id AND material.attribute_id = 68 AND material.int_value IN (426,463,465,459,418,460))
JOIN ProductAttribute length ON (P.id = length.product_id AND length.attribute_id = 85 AND length.float_value > 10 AND length.float_value < 49)
JOIN ProductAttribute height ON (P.id = height.product_id AND height.attribute_id = 102 AND height.float_value > 78 AND height.float_value < 186)
JOIN ProductAttribute weight ON (P.id = weight.product_id AND weight.attribute_id = 119 AND weight.float_value > 10 AND weight.float_value < 15)
JOIN ProductAttribute waterproof ON (P.id = waterproof.product_id AND waterproof.attribute_id = 136 AND waterproof.bool_value = 1)
JOIN ProductAttribute tags ON (P.id = tags.product_id AND tags.attribute_id = 153 AND tags.string_value LIKE '%alluring%')
;
SELECT P.id FROM Product P
JOIN AttributeIndex AI ON (P.id = AI.product_id)
WHERE 
AI.color IN (152,146,101,152,118,109) 
AND AI.size IN (288,210,246,275,258,289) 
AND AI.brand IN (305,303,300,375,308,340) 
AND AI.material IN (426,463,465,459,418,460) 
AND AI.length > 10 AND AI.length < 49 
AND AI.height > 78 AND AI.height < 186 
AND AI.weight > 10 AND AI.weight < 15 
AND AI.waterproof = 1 
AND AI.tags LIKE '%alluring%';
CREATE TABLE `Product` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(150) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB

CREATE TABLE `ProductAttribute` (
  `product_id` int(11) NOT NULL,
  `attribute_id` smallint(6) DEFAULT NULL,
  `int_value` int(11) DEFAULT NULL,
  `float_value` float DEFAULT NULL,
  `bool_value` tinyint(1) DEFAULT NULL,
  `string_value` varchar(255) DEFAULT NULL,
  KEY `PA` (`product_id`,`attribute_id`)
) ENGINE=InnoDB

CREATE TABLE `AttributeIndex` (
  `product_id` int(11) NOT NULL,
  `color` int(11) DEFAULT NULL,
  `size` int(11) DEFAULT NULL,
  `brand` int(11) DEFAULT NULL,
  `material` int(11) DEFAULT NULL,
  `length` float DEFAULT NULL,
  `height` float DEFAULT NULL,
  `weight` float DEFAULT NULL,
  `waterproof` tinyint(1) DEFAULT NULL,
  `tags` varchar(255) DEFAULT NULL,
  KEY `P` (`product_id`)
) ENGINE=InnoDB