这是一个数据库设计和查询设计问题,但制定起来有点困难。
我正在调查语言中元音声音之间的关系。每个元音可以通过其在二维元音空间中的位置来描述。一个维度是“高度”,通常由“打开”和“关闭”之间的5个位置表示。第二个维度是“背面”,通常由“后面和前面”之间的3个位置表示。因此,元音可以有3 x 5 = 15个位置。它也可以是圆形或不圆形,因此给出30个排列(在极其简单的模型中) )。
我希望看到仅通过一个步骤在一个尺寸中移动参数的效果,即高度移动一步或者背移移动一步或者切换圆形/不接地属性。在每种情况下,其他两个参数都不受影响。
我在数据库中有几十万个单词,理论上已知元音位置(即我可以按照我想要的方式映射它们,最明显的是高度和背景的整数值以及舍入/舍入的布尔值)
现在我想查找数据库中的单词,其中(最后一个)元音满足上述与我选择的元音有关的标准。
如果我们说我使用的元音在矩阵上是2,2并且是四舍五入的,那么sql看起来像这样:
SELECT word FROM mytable WHERE (rounded = false AND height = 2 AND backness = 3)
OR (rounded = true AND height = 2 AND (bacKness = 1 OR backness = 3))
OR (rounded = true AND backness = 2 AND (height = 1 OR height = 3))
显然,这可以完成这项工作,并且以编程方式执行它没有任何问题(特别是因为矩阵大小之外的值根本不匹配,这很好)。
我想知道的是,如果我使用更逼真的6 x 10矩阵并允许多个自由度,这些查询是否变得不切实际并且表现不佳。
有没有人知道用SQL表示和查询矩阵数据的最佳方法?
我希望我已经中途清楚了!
答案 0 :(得分:1)
SELECT matched.word
FROM mytable orig,
mytable matched
WHERE (
(matched.rounded <> orig.rounded)
+
(abs(matched.height - orig.height) > 1) /* validate "height" */
+
(abs(matched.backness - orig.backness) > 1) /* validate "backness" */
/* + (...) add more column conditions here if you need */
) = 1 /* this is how many columns can be different */
使用此查询,您只需定义要包含在比较中的列以及您希望允许的差异数。
请注意,在结果中,您将获得恰好有1列不同(不少于,不多于)的单词列表。如果您想在结果中包含没有差异的行,请在结尾处将“= 1”更改为“&lt; = 1”。
abs(matched.height - orig.height) > 1
条件意味着列height
中的差异大于1,对于此列,条件会将差异总数增加1。
您还可以更改每个列条件(从“&gt; 1”到更大的值),因此它允许更大范围的单列值差异。
答案 1 :(得分:1)
只要您有适当的索引,就可以了。你问,什么是合适的指数?好问题!您需要在backness
,height
和rounded
的所有三个上至少有一个索引。对于显示的查询,它将取决于优化程序的优秀程度。
SELECT word
FROM mytable
WHERE (rounded = false AND height = 2 AND backness = 3)
OR (rounded = true AND height = 2 AND (backness = 1 OR backness = 3))
OR (rounded = true AND backness = 2 AND (height = 1 OR height = 3))
如果优化器将查询重写为:
SELECT word
FROM mytable
WHERE (rounded = false AND height = 2 AND backness = 3)
OR (rounded = true AND height = 2 AND backness = 1)
OR (rounded = true AND height = 2 AND backness = 3)
OR (rounded = true AND backness = 2 AND height = 1)
OR (rounded = true AND backness = 2 AND height = 3)
然后可以修改为:
SELECT word
FROM mytable
WHERE (rounded = false AND height = 2 AND backness = 3)
OR (rounded = true AND height = 2 AND backness = 1)
OR (rounded = true AND height = 2 AND backness = 3)
OR (rounded = true AND height = 1 AND backness = 2)
OR (rounded = true AND height = 3 AND backness = 2)
然后它可以以任何顺序有效地使用列的索引。另一方面,如果优化器不能进行这样的重写,那么它可能会回退到表扫描上。此时,您必须研究SQLite优化器的优秀程度。有了几十万条记录,在中途不错的机器上(比如,一个来自这个千年,或者最好是这个十年),不应该有太多的问题 - 几乎所有的数据库都应该适合内存(如果是SQLite)使用内存缓存来处理数据)。它取决于与每个单词相关的其他数据。
如果您最终只对三个属性中的两个进行了查询,那么您需要索引使其列的前两个列为您引用的列(因此,如果您引用backness
和{ {1}},您需要将索引放在rounded
或(backness, rounded, height)
上,这样索引仍然可以使用。从极端情况来看,这可能意味着7个索引(单列3个,每个索引3个)一对列,在所有三列上都有1个。)它会“工作”;它可能会使用更多的磁盘空间存储索引,而不是存储它们所带来的性能提升所保证的,以及每次插入时必须更新7个索引所带来的性能损失一行或修改一行的元音声音属性。
OR公式可能会给DBMS优化器带来麻烦。嵌套的OR公式可能会导致更多麻烦。正如最初编写的那样,您可以使用单个索引并不是很明显。但这一切都取决于DBMS和优化器。
查看UNION(或UNION ALL)如何与替代品进行查询。
(rounded, backness, height)
UNION ALL是安全的,甚至可能是明智的,因为UNION中每个术语的单词列表给出了一组不相交的单词(没有重复 - 除非使用不同的元音属性给出相同的单词)。
您还可以使用查询原始变体中的OR'd术语尝试UNION。