优化棘手的SQL搜索查询

时间:2013-06-13 12:50:15

标签: sql optimization query-optimization sql-optimization

我正在尝试针对以下问题提出一个简单,高效的查询:

假设有几个实体(项目)都具有唯一ID。实体具有一组可变属性(属性),因此已将其移动到单独的表中:

T_Items_Props
=======================
Item_ID  Prop_ID  Value
-----------------------
101      1        'abc'
101      2        '123'
102      1        'xyz'
102      2        '123'
102      3        '102'
...      ...      ...

现在我想搜索符合某些指定搜索条件的项目,如下所示:

<<Pseudo-SQL>>

SELECT Item_Id(s)
  FROM T_Items_Props
 WHERE Prop 1 = 'abc'
   AND Prop 2 = '123'
     ...
   AND Prop n = ...

如果我有一个像Items(Id, Prop_1, Prop_2, ..., Prop_n)这样的表格,这将相当容易。然后我可以做一个简单的SELECT,其中搜索条件可以简单地(甚至以编程方式)插入WHERE - 子句中,但在这种情况下,我必须做类似的事情:

SELECT t1.Item_ID
  FROM T_Items_Props t1
     , T_Items_Props t2
     , ...
     , T_Items_Props tn -- (depending on how many properties to compare)
   AND t1.Item_ID = t2.Item_ID
   AND t1.Prop_ID = 1 AND t1.Value = 'abc'
   AND t2.Prop_ID = 2 AND t2.Value = '123'
     ...
   AND tn.Prop_ID = n AND tn.Value = ...

有更好/更简单/更快的方法吗?

4 个答案:

答案 0 :(得分:2)

为了使查询更具可读性,您可以执行以下操作:

SELECT 
    t1.Item_ID
FROM 
    T_Items_Props t1
where convert(varchar(10), t1.Item_ID) + ';' + t1.Value in (
    '1;abc',
    '2;123',
    ...
)

注意:这假设您的ID不会超过10个digets。由于额外的类型转换和字符串连接,它也可能会降低查询速度。

答案 1 :(得分:1)

您可以计算正确道具的数量。如果可能存在重复,这不是很好。 E.g:

Prop_ID = 1 AND Value = 'abc'
Prop_ID = 2 AND Value = '123'

,表格如下:

T_Items_Props
=======================
Item_ID  Prop_ID  Value
-----------------------
101      1        'abc'
101      1        'abc'

这将是真的,虽然它不应该。

但是,如果你想尝试一下,这是如何:

SELECT nested.* FROM (
SELECT item_id, count(*) AS c FROM t_items_props
WHERE ((prop = 1 AND value = 'abc')
OR (prop = 2 AND value = '123')
... more rules here ...)
GROUP BY item_id) nested
WHERE nested.c > 2 ... number of rules ...

答案 2 :(得分:0)

您可以将join语句与过滤或分面搜索结合使用。它提供了更好的性能,因为您可以限制搜索空间。这是一个很好的例子:Faceted Search (solr) vs Good old filtering via PHP?

答案 3 :(得分:0)

我在之前的类似查询意图的帖子中提到了这一点。用户可以一次有2个条件,另有5个条件,并且想要一种简单的方法来构建SQL命令。为了简化必须添加FROM表并更新WHERE子句的需要,您可以通过连接简化并将该条件放在连接级别......所以,每个条件都是它自己的集合添加到混合中。

SELECT 
      t1.Item_ID
   FROM 
      T_Items_Props t1

         JOIN T_Items_Props t2
            on t1.Item_ID = t2.Item_ID
           AND t2.Prop_ID = 2
           AND t2.Value = '123'

         JOIN T_Items_Props t3
            on t1.Item_ID = t3.Item_ID
           AND t3.Prop_ID = 6
           AND t3.Value = 'anything'

         JOIN T_Items_Props t4
            on t1.Item_ID = t4.Item_ID
           AND t4.Prop_ID = 15
           AND t4.Value = 'another value'
   WHERE
          t1.Prop_ID = 1
      AND t1.Value = 'abc'

请注意,主查询始终以最小的“T1”属性/值标准开始,但是,请注意JOIN子句......它们实际上是相同的,因此通过循环很容易实现。根据需要保持对T2,T3,T4的混叠。这将从符合T1标准的任何项目开始,但也需要找到所有其余项目。