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

时间:2016-11-22 10:44:20

标签: php mysql search entity-attribute-value

我想找到一种有效的方法来按数据库中的属性搜索产品,其中数据按EAV model进行组织。

有2个表:

  • 产品,存储产品,有产品ID。
  • ProductAttribute - 产品的属性值。

SQL:

CREATE TABLE `Product` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(150) DEFAULT NULL,
  PRIMARY KEY (`id`)
)

CREATE TABLE `ProductAttribute` (
  `product_id` int(11) NOT NULL,
   # in real code it's attribute_id and value_id,
   # I just simplified this
  `attribute` varchar(10), 
  `value` varchar(255)
)

不同的产品可以具有不同数量的属性。 E. g。产品' T恤'有尺寸和颜色,无论是产品还是笔记本电脑'有cpu和ram。产品可以有10个以上的属性。

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

我的问题是从这些表中搜索MySQL的查询效率很低。按10个产品属性搜索需要使用ProductAttribute表进行10个JOINS:

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,但我不限于此 - 任何解决方案都会很有趣。

更新 :( SPOILER:如果此任务存在任何搜索引擎/索引器,我仍然感兴趣)我创建了多个JOINS查询的比较测试和索引表查询。索引表是一个表,其中所有属性都是单独的列。结果:JOINS - 4.5s,索引表 - 0.2s。 See it on github

使用JOIN进行的示例查询:

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%')
;

执行4.5秒。

按索引表查询示例:

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%';

执行时需要0.2秒。

CREATE TABLE for tests(有关github的更多信息):

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

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

0 个答案:

没有答案