需求:搜索商品,首先根据关键字(品名,材质,规格,钢厂,仓库,公司名)进行模糊查询,需要返回筛选条件,返回的筛选条件为品类,品名(多选),材质(多选),钢厂(多选)。然后根据品类,品名,材质,钢厂,地区,在一次进行精确搜索。
表设计
CREATE TABLE `steels_shopping` ( `id` int(50) NOT NULL AUTO_INCREMENT COMMENT '主键 ', `shopping_id` varchar(50) DEFAULT NULL COMMENT '商品id', `shopping_name` varchar(50) DEFAULT NULL COMMENT '商品名称', `product_name` varchar(50) DEFAULT NULL COMMENT '品名', `material` varchar(50) DEFAULT NULL COMMENT '材质', `manufactor` varchar(50) DEFAULT NULL COMMENT '钢厂/厂家', `warehouse` varchar(50) DEFAULT NULL COMMENT '仓库', `shop_type` varchar(50) DEFAULT NULL COMMENT '店铺分类', `unit` varchar(20) DEFAULT NULL COMMENT '单位(详见字典表WEIGHT_UNIT)', `stock` varchar(20) DEFAULT NULL COMMENT '库存', `starting_quantity` varchar(50) DEFAULT NULL COMMENT '起订量', `weighting_method` varchar(20) DEFAULT NULL COMMENT '计重方式(详见字典表WEIGHTING_METHOD)', `quality_grade` varchar(20) DEFAULT NULL COMMENT '质量等级(详见字典表QUALITY_GRADE)', `warranty` varchar(20) DEFAULT NULL COMMENT '质保书(详见字典表WARRANTY)', `shopping_detail` varchar(9000) DEFAULT NULL COMMENT '商品详情', `shopping_abbr` varchar(300) DEFAULT NULL COMMENT '商品缩略图', `is_shelf` varchar(1) DEFAULT 'Y' COMMENT '是否上架(Y是 N否)', `is_hot` varchar(1) DEFAULT 'Y' COMMENT '是否热销(Y是 N否)', `is_new` varchar(1) DEFAULT 'Y' COMMENT '是否新品(Y是 N否)', `is_main` varchar(1) DEFAULT NULL COMMENT '是否主打产品(Y是 N否)', `order` int(10) DEFAULT '100' COMMENT '排序', `key_word` varchar(200) DEFAULT NULL COMMENT '关键字', `shopping_status` varchar(10) DEFAULT NULL COMMENT '审核状态(详见字典表SHOPPING_STATUS)', `volume` int(10) DEFAULT '0' COMMENT '销量', `created_by` varchar(50) DEFAULT NULL COMMENT '创建人', `updated_by` varchar(50) DEFAULT NULL COMMENT '修改人', `created_time` datetime DEFAULT NULL COMMENT '创建时间', `updated_time` datetime DEFAULT NULL COMMENT '修改时间', PRIMARY KEY (`id`) USING BTREE, UNIQUE KEY `STEELS_SHOPPING_SHOPPING_ID` (`shopping_id`) USING BTREE, KEY `STEELS_SHOPPING_CREATED_BY` (`created_by`) USING BTREE, KEY `STEELS_SHOPPING_IS_SHELF` (`is_shelf`) ) ENGINE=InnoDB AUTO_INCREMENT=3942 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='商品表';
CREATE TABLE `steels_shopping_attribute` (
`id` int(50) NOT NULL AUTO_INCREMENT COMMENT '主键 ',
`shopping_attribute_id` varchar(50) DEFAULT NULL COMMENT '商品id',
`shopping_id` varchar(50) DEFAULT NULL COMMENT '商品id',
`shopping_attribute_type` varchar(50) DEFAULT NULL COMMENT '商品属性类型(详见字典表SHOPPING_ATTRIBUTE_TYPE)',
`shopping_attribute_main_type` varchar(50) DEFAULT NULL COMMENT '商品属性主类型(详见字典表SHOPPING_ATTRIBUTE_MAIN_TYPE)',
`shopping_attribute_name` varchar(50) DEFAULT NULL COMMENT '商品属性名称',
`inclusive_price` double(20,2) DEFAULT NULL COMMENT '含税价格(只有当商品属性主类型是规格的时候才有数据)',
`stock` int(20) DEFAULT NULL COMMENT '库存(只有当商品属性主类型是规格的时候才有数据)',
`is_custom_input` varchar(1) DEFAULT NULL COMMENT '是否可自定义输入(Y是 N否)',
`created_by` varchar(50) DEFAULT NULL COMMENT '创建人',
`updated_by` varchar(50) DEFAULT NULL COMMENT '修改人',
`created_time` datetime DEFAULT NULL COMMENT '创建时间',
`updated_time` datetime DEFAULT NULL COMMENT '修改时间',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `STEELS_SHOPPING_ATTRIBUTE_SHOPPING_ATTRIBUTE_ID` (`shopping_attribute_id`),
KEY `STEELS_SHOPPING_ATTRIBUTE_SHOPPING_ID` (`shopping_id`) USING BTREE,
KEY `STEELS_SHOPPING_ATTRIBUTE_CREATED_BY` (`created_by`) USING BTREE,
KEY `STEELS_SHOPPING_ATTRIBUTE_MAIN_TYPE` (`shopping_attribute_main_type`)
) ENGINE=InnoDB AUTO_INCREMENT=86243 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='商品属性表';
CREATE TABLE `steels_company_attribute` (
`id` int(50) NOT NULL AUTO_INCREMENT COMMENT '主键 ',
`company_attribute_id` varchar(50) DEFAULT NULL COMMENT '公司属性id',
`company_id` varchar(50) DEFAULT NULL COMMENT '公司id',
`company_attribute_name` varchar(50) DEFAULT NULL COMMENT '公司属性名称',
`company_attribute_type` varchar(50) DEFAULT NULL COMMENT '公司属性类型',
`created_by` varchar(50) DEFAULT NULL COMMENT '创建人',
`updated_by` varchar(50) DEFAULT NULL COMMENT '修改人',
`created_time` datetime DEFAULT NULL COMMENT '创建时间',
`updated_time` datetime DEFAULT NULL COMMENT '修改时间',
PRIMARY KEY (`id`) USING BTREE,
KEY `STEELS_COMPANY_ATTRIBUTE_CREATED_BY` (`created_by`) USING BTREE,
KEY `STEELS_COMPANY_ATTRIBUTE_COMPANY_ID` (`company_id`) USING BTREE,
KEY `STEELS_COMPANY_ATTRIBUTE_COMPANY_ATTRIBUTE_TYPE` (`company_attribute_type`)
) ENGINE=InnoDB AUTO_INCREMENT=6102 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='公司属性表';
CREATE TABLE `steels_dictionary` (
`id` int(50) NOT NULL AUTO_INCREMENT COMMENT '主键',
`tree_id` varchar(100) DEFAULT NULL COMMENT '树id',
`parent_id` varchar(50) DEFAULT NULL COMMENT '父级id',
`group` varchar(50) DEFAULT NULL COMMENT '分组',
`value` varchar(50) DEFAULT NULL COMMENT '值',
`name` varchar(50) DEFAULT NULL COMMENT '名称',
`comment` varchar(50) DEFAULT NULL COMMENT '描述',
`order` int(50) DEFAULT NULL COMMENT '排序',
`is_default` varchar(1) DEFAULT NULL COMMENT '是否默认',
PRIMARY KEY (`id`) USING BTREE,
KEY `STEELS_DICTIONARY_GROUP` (`group`) USING BTREE,
KEY `STEELS_DICTIONARY_VALUE` (`value`)
) ENGINE=InnoDB AUTO_INCREMENT=384 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='字典表';
sql,筛选条件
select
group_concat(distinct s.shop_type) typeName,
group_concat(distinct s.product_name) productName,
group_concat(distinct s.material) material,
group_concat(distinct s.manufactor) manufactor
from
steels_shopping s,
steels_shopping_attribute sa,
steels_company c,
steels_company_attribute ca,
steels_dictionary d
where
s.shopping_id = sa.shopping_id and
sa.shopping_attribute_main_type = 'SPEC' and
s.created_by = c.created_by and
c.company_id = ca.company_id and
ca.company_attribute_type = 'SALE_REGION' and
d.`value` = ca.company_attribute_name and
d.`group` = 'PURCHASE_REGION'
<if test="pcSearchShoppingParamDTO.type != null and pcSearchShoppingParamDTO.type != ''">
and s.shop_type = #{pcSearchShoppingParamDTO.type}
</if>
<if test="pcSearchShoppingParamDTO.productName != null and pcSearchShoppingParamDTO.productName.size > 0">
and s.product_name in
<foreach item="productName" collection="pcSearchShoppingParamDTO.productName" separator="," open="(" close=")" index="">
#{productName}
</foreach>
</if>
<if test="pcSearchShoppingParamDTO.material != null and pcSearchShoppingParamDTO.material.size > 0">
and s.material in
<foreach item="material" collection="pcSearchShoppingParamDTO.material" separator="," open="(" close=")" index="">
#{material}
</foreach>
</if>
<if test="pcSearchShoppingParamDTO.manufactor != null and pcSearchShoppingParamDTO.manufactor.size > 0">
and s.manufactor in
<foreach item="manufactor" collection="pcSearchShoppingParamDTO.manufactor" separator="," open="(" close=")" index="">
#{manufactor}
</foreach>
</if>
<if test="pcSearchShoppingParamDTO.spec != null and pcSearchShoppingParamDTO.spec.size > 0">
and sa.shopping_attribute_name in
<foreach item="spec" collection="pcSearchShoppingParamDTO.spec" separator="," open="(" close=")" index="">
#{spec}
</foreach>
</if>
<if test="pcSearchShoppingParamDTO.warehouse != null and pcSearchShoppingParamDTO.warehouse != ''">
and s.warehouse = #{pcSearchShoppingParamDTO.warehouse}
</if>
<if test="pcSearchShoppingParamDTO.companyName != null and pcSearchShoppingParamDTO.companyName != ''">
and c.company_name = #{pcSearchShoppingParamDTO.companyName}
</if>
<if test="pcSearchShoppingParamDTO.keyWord != null and pcSearchShoppingParamDTO.keyWord != ''">
and s.key_word like concat("%",#{pcSearchShoppingParamDTO.keyWord},"%")
</if>
sql:返回数据
select
s.shopping_id shoppingId,
s.shopping_name shoppingName,
s.shopping_abbr shoppingAbbr,
sa.inclusive_price price,
d1.`comment` unit,
s.warehouse,
c.company_id companyId,
c.company_name companyName
from
steels_shopping s,
steels_shopping_attribute sa,
steels_company c,
steels_company_attribute ca,
steels_dictionary d,
steels_dictionary d1
where
s.shopping_id = sa.shopping_id and
s.created_by = c.created_by and
sa.shopping_attribute_main_type = 'SPEC' and
c.company_id = ca.company_id and
ca.company_attribute_type = 'SALE_REGION' and
d.`value` = ca.company_attribute_name and
d.`group` = 'PURCHASE_REGION' and
d1.`value` = s.unit and
d1.`group` = 'WEIGHT_UNIT' and
s.is_shelf = 'Y'
<if test="pcSearchShoppingParamDTO.type != null and pcSearchShoppingParamDTO.type != ''">
and s.shop_type = #{pcSearchShoppingParamDTO.type}
</if>
<if test="pcSearchShoppingParamDTO.productName != null and pcSearchShoppingParamDTO.productName.size > 0">
and s.product_name in
<foreach item="productName" collection="pcSearchShoppingParamDTO.productName" separator="," open="(" close=")" index="">
#{productName}
</foreach>
</if>
<if test="pcSearchShoppingParamDTO.material != null and pcSearchShoppingParamDTO.material.size > 0">
and s.material in
<foreach item="material" collection="pcSearchShoppingParamDTO.material" separator="," open="(" close=")" index="">
#{material}
</foreach>
</if>
<if test="pcSearchShoppingParamDTO.manufactor != null and pcSearchShoppingParamDTO.manufactor.size > 0">
and s.manufactor in
<foreach item="manufactor" collection="pcSearchShoppingParamDTO.manufactor" separator="," open="(" close=")" index="">
#{manufactor}
</foreach>
</if>
<if test="pcSearchShoppingParamDTO.spec != null and pcSearchShoppingParamDTO.spec.size > 0">
and sa.shopping_attribute_name in
<foreach item="spec" collection="pcSearchShoppingParamDTO.spec" separator="," open="(" close=")" index="">
#{spec}
</foreach>
</if>
<if test="pcSearchShoppingParamDTO.warehouse != null and pcSearchShoppingParamDTO.warehouse != ''">
and s.warehouse = #{pcSearchShoppingParamDTO.warehouse}
</if>
<if test="pcSearchShoppingParamDTO.companyName != null and pcSearchShoppingParamDTO.companyName != ''">
and c.company_name = #{pcSearchShoppingParamDTO.companyName}
</if>
<if test="pcSearchShoppingParamDTO.keyWord != null and pcSearchShoppingParamDTO.keyWord != ''">
and s.key_word like concat("%",#{pcSearchShoppingParamDTO.keyWord},"%")
</if>
<if test="pcSearchShoppingParamDTO.area != null and pcSearchShoppingParamDTO.area != ''">
and d.`comment` = #{pcSearchShoppingParamDTO.area}
</if>
GROUP BY s.shopping_id
order by sa.inclusive_price
<choose>
<when test="pcSearchShoppingParamDTO.order != null and pcSearchShoppingParamDTO.order != ''">
<choose>
<when test='pcSearchShoppingParamDTO.order == "DESC" or pcSearchShoppingParamDTO.order == "ASC"'>
${pcIndexSupplyProductsParamDTO.order}
</when>
<otherwise>
desc
</otherwise>
</choose>
</when>
<otherwise>
desc
</otherwise>
</choose>
筛选条件sql用时0.7s左右,返回数据sql用时1.4s左右,接口调用用时2s左右,商品表3807条数据,商品属性表83741条数据,公司表108条数据,公司属性表里面3029条数据,字典表350条数据,不分组查询数据量为94820条,通过分组查询为3793条,索引该创建的都创建了,该使用的也使用了
只是一个小白,在大公司搜索都接触不到,现在在小公司啥都要自己做,才发现原来优化一条sql这么难,这问题弄了三天了,还是没有找到解决的方法
看了你的sql,都会产生笛卡尔积,你可以使用left join或者right join 试试
建议尝试使用elasticSearch