【问题标题】:Efficient method of finding database rows that have *one or more* qualities from a list of seven qualities从七种品质的列表中查找具有*一种或多种*品质的数据库行的有效方法
【发布时间】:2011-01-14 00:45:30
【问题描述】:

对于这个问题,我想看看是否有人对如何实施我目前计划实施的内容有更好的了解(如下):

我正在使用数据库跟踪一组图像。每张图片由一行表示。

我希望能够使用许多不同的搜索参数来搜索图像。这些参数之一涉及按颜色搜索选项。 (其余的搜索内容目前工作正常。)

此数据库中的图像最多可以包含七种颜色:

-红色

-橙色

-黄色

-绿色

-蓝色

-靛蓝

-紫罗兰


以下是一些示例用户查询:

“我想要一张包含红色的图片。”

“我想要一张包含红色和蓝色的图像。”

“我想要一张包含黄色和紫色的图像。”

“我想要一张包含红色、橙色、黄色、绿色、蓝色、靛蓝和紫色的图像。”


等等。用户通过使用 html 表单中的复选框来进行此选择。他们可以检查零个复选框,所有七个,以及介于两者之间的任何东西。

我很想知道人们认为执行此数据库搜索的最有效方法是什么。

我现在有两种可能的选择,但我觉得肯定有更好的东西我没有想到。

(选项 1)
- 对于每一行,只需在数据库中有七个附加字段,每种颜色一个。每个字段都有一个 1 或 0(真/假)值,我根据用户勾选的内容进行选择。 (我不太喜欢这个解决方案,因为添加七个额外字段似乎有点浪费......特别是因为这个表中的大多数图片最多只能有 3-4 种颜色,尽管有些可以 最多有 7 个。所以这意味着我要存储很多零。)另外,如果我稍后添加更多可搜索的颜色(我不认为我会这样做,但总是有可能的),我必须添加更多字段。

(选项 2)
- 对于每个图像行,我可以有一个“颜色”文本字段,用于存储以空格分隔的颜色名称(或为紧凑起见的数字)。然后我可以通过字段进行全文匹配,选择包含“红黄绿”(或“1 3 4”)的行。但是我有点不想进行全文搜索,因为我已经允许关键字搜索,而且我真的不想在每个图像搜索中进行两次全文搜索。另外,如果数据库变大,全文内容可能会变慢。

还有没有更好的选择?

谢谢!

旁注:我正在使用 PHP 来处理 MySQL 数据库。

【问题讨论】:

  • 当你说“我想要一个包含红色的图像”时,你真的是说你想要一个包含红色但没有其他颜色的图像(可以这么说)?
  • 不,在这种情况下,我的意思是我想要任何包含任何红色的图像(无论是[只有红色],还是[红色和蓝色和黄色])。

标签: php mysql search


【解决方案1】:

您可以创建第二个名为颜色的表。

  colors = (color_id, name)

还有一个名为 image_colors 的关系表。

  image_colors = (image_id, color_id)

然后在 image_colors 表中为每个图像的每种颜色添加一行。

 image_colors
 Image_id     Color_id
  1            1
  2            3
  2            4

所以图片 1 有一种颜色,而图片 2 有两种颜色。

要找到颜色为 4 和 5 的图像,您可以

    select  i.fileName, etc
    from images i JOIN image_colors c ON
         i.image_id = c.image_id
    where
         c.color_id = 4 OR
         c.color_id = 5

这种解决方案的优点是查询方便。

【讨论】:

  • 我喜欢这种方法!如果在 php 方面,我通过数字而不是名称来指代颜色,我什至可以将其设为一张而不是两张。我唯一担心的是 image_colors 表的大小可能很大。你认为我可以看到大量图像对性能的重大影响吗?例如,如果我有 100 万张图像,那可能意味着我可能在 image_colors 表中有 400 万行(假设每个图像平均有 4 种颜色)?如果我在做 color = 1 OR color = 5 OR color = 7,你认为这会导致回报缓慢吗? (随着时间的推移还有更多的照片?)
  • MySQL 就是为处理这些大表而设计的,并且具有索引等许多功能,可以大大加快查询速度。如果您要一直查询某个字段,那么您通常会为该字段添加一个索引,这应该会提高速度。
  • @Vincent Ramdhanie 哦,是的,哈哈。我肯定在使用索引。 :) 我只是不知道在百万行以上的场景中我会看到什么样的减速。
  • @Mike CHAR(1) 可能比 TINYINT(1) 更好?
  • CHAR(1) 在颜色方面可能比 int 更好。或不。我可以想象人们想要搜索黑色、棕色、棕褐色、柠檬绿。 . .我不确定将您的设计限制为 7 种颜色是否适合实际使用。
【解决方案2】:

假设颜色列表永远不会(或很少)改变,向图像表添加 7 个额外的列可能更有效。对每个查询进行规范化后的连接和重复数据删除通常比将行宽 7 个字段所产生的额外 I/O 成本更高。

不管怎样,如果您有机会转到 Oracle,bitmap indexes 就是为这种事情而构建的。

【讨论】:

  • 我猜在性能方面,七列方法很好,但我不喜欢用完所有空间的想法。我也同意 JOIN 权衡。你说的对。此外,Oracle 位图索引很酷! :)
【解决方案3】:

您可以存储一个额外的 INT 字段并存储 1 个数字,该数字表示关联颜色的标志位定义。搜索时,您只需执行相同的按位运算即可查询特定的整数值。

查看 Mark Cain 对此 MySql 参考手册页的评论,了解我的建议:

http://dev.mysql.com/doc/refman/5.0/en/bit-functions.html

【讨论】:

  • @Tahbaza 我实际上也考虑过一些事情,但我不知道如何在查询的 WHERE 子句中执行任何按位操作。你知道做这样的事情有多有效吗(我用更易读的语法而不是按位的东西): int 的第一个数字是 1 而 int 的第五个数字是 1 ?实际上,我的建议甚至可能吗?我希望我没有误解你的建议。
  • @HiThere:你明白我的意思,但我不会在 SQL 中进行按位运算,在你的屏幕上,你的标准可能是一个复选框列表。只需在代码中进行按位整数计算,并将其作为参数作为 where 子句的一部分传递给您的查询。我会给你一个按位算法的例子,但我不是 php 开发人员。这是一个涵盖它的链接php.net/manual/en/language.operators.bitwise.php
  • @Tahbaza 感谢您的链接!不过有一件事我不太明白。虽然我可以看到这种方法如何给我,比如说,只有红色和蓝色的图片,但我不确定如何将按位整数计算的结果传递给 mysql 查询会给我所有包含红色或蓝色的图片. (而且,你知道使用按位运算结果进行比较涉及到什么 WHERE 子句语法吗?我不知道该去哪里。)
  • @HiThere:您需要为应该与红色和蓝色关联的行(以及表中的每一行)保存一个适合红色和蓝色的整数值。由于您将在构建 SQL 之前计算整数值,就您的数据库而言,您只需测试 INT 列是否在所需的颜色标志位置有位,例如WHERE ColorFlags & 8,其中 8 位置对应于颜色标准的标志。我已将我的答案的链接添加到具有更全面示例的页面。
  • @Tahbaza 啊,我明白了!感谢您的解释。这将是一种非常有趣的做事方式。
猜你喜欢
  • 1970-01-01
  • 2017-03-14
  • 1970-01-01
  • 2011-09-08
  • 1970-01-01
  • 1970-01-01
  • 2012-04-08
  • 2010-10-16
相关资源
最近更新 更多