最佳性能SQL

时间:2015-05-12 20:04:23

标签: sql

我有一个包含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_idtopic='topic1'以及product='product2'
  • 取得segment='Segment1'的全部内容

我正在尝试自我加入和相关查询,但我不确定应该继续哪个方向以获得最佳性能。任何帮助将不胜感激。

3 个答案:

答案 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_idkey_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的选择性高于topicsegment