我有一个包含3列的表格:
item_id (decimal), key_name (varchar), key_string_value (varchar)
它包含数百和数千行。下面是前6行,可以让您了解数据。
1. 1 product product1
2. 1 topic topic1
3. 1 segment segment1
4. 2 product product2
5. 2 topic topic1
6. 2 segment segment1
每个不同的item_id
都有3行与之关联,并使用主题,产品,细分等元数据对其进行描述。我正在尝试编写一个SQL查询,它执行以下操作并执行得非常好。
现在我需要选择所有item_ids,这些元素足以满足这些元数据的特定组合,例如:
item_id
和topic='topic1'
以及product='product2'
segment='Segment1'
的全部内容
我正在尝试自我加入和相关查询,但我不确定应该继续哪个方向以获得最佳性能。任何帮助将不胜感激。
答案 0 :(得分:1)
您可以使用HAVING
和条件聚合:
SELECT item_id
FROM YourTable
GROUP BY item_id
HAVING MAX(CASE WHEN key_name = 'topic' AND key_string_value ='topic1' THEN 1 END) = 1
AND MAX(CASE WHEN key_name = 'product' AND key_string_value ='product2' THEN 1 END) = 1
AND MAX(CASE WHEN key_name = 'segment' AND key_string_value ='segment1' THEN 1 END) = 1
性能最好吗?将不得不测试,但我希望它能击败自连接和相关子查询。
答案 1 :(得分:1)
相关子查询通常是解决任何问题的性能最低的解决方案,除非DB可以将它们转换为连接,因为某些查询规划器在某些情况下可以执行此操作。但是,在任何优化过程中,使用DB的机制(例如某些数据库中的EXPLAIN PLAN
)检查和比较数据库实际为不同查询和不同条件提出的计划是明智的。
我完成这项任务的第一步将采用以下形式:
SELECT product.item_id
FROM
(
SELECT item_id
FROM my_table
WHERE key_name = 'product' AND key_string_value = 'product2'
) product
JOIN (
SELECT item_id
FROM my_table
WHERE key_name = 'topic' AND key_string_value = 'topic1'
) topic
ON product.item_id = topic.item_id
JOIN (
SELECT item_id
FROM my_table
WHERE key_name = 'segment' AND key_string_value = 'segment1'
) segment
ON topic.item_id = segment.item_id
假设该表在(item_id, key_name)
上具有主键约束 - 或者至少是唯一性约束 - ;如果它没有,则内联视图应使用SELECT DISTINCT
。此外,它可能会从(key_name)
上的索引中获益,甚至可能会从(key_name, key_string_value)
上的索引获益更多。
在你疯狂创建索引之前,请确保你明白,虽然可以加速查询,但他们做会减慢插入,更新和删除的速度,并且会增加数据库的足迹。再次,检查查询计划,测试性能。
<强>更新强>:
鉴于我们现在发现(key_name, key_string_value)
确实有一个索引,并且各种key_string_value
s使得这样的索引具有高度选择性,我倾向于认为上述方法会做很好。测试时,如果您不能依赖内联视图以避免提供重复的SELECT DISTINCT
,请不要忘记item_id
。
答案 2 :(得分:0)
首先:我认为这个没有item_id
索引的效果很好的解决方案,所以我认为你应该将你的PK改为(item_id, key_name)
的合成 - 你无论如何,这需要它是唯一的。
假设您已经这样做了,我们现在可以快速跟踪item_id
和key_name
,我认为这是必要的。
我们现在可以尝试自我加入,这应该会给MySQL带来很好的结果,就像在InnoDB中一样,所有复合索引都是聚集的:
SELECT
one.item_id
FROM table_name AS one
INNER JOIN table_name AS two
ON two.item_id=one.item_id
INNER JOIN table_name AS three
ON three.item_id=one.item_id
WHERE one.key_name='product'
AND one.key_string_value='product1'
AND two.key_name='topic'
AND two.key_string_value='topic1'
AND three.key_name='segment'
AND three.key_string_value='segment1'
;
将具有最高选择性的选择器应用于驱动表非常重要。即one
- 在我的查询中,我假设product
的选择性高于topic
或segment
。