在什么情况下,可能性()有用?

时间:2014-01-07 20:24:38

标签: sqlite query-optimization

通过sqlite文档阅读我发现了以下函数:

http://www.sqlite.org/lang_corefunc.html#likelihood

  

似然(X,Y)函数返回参数X不变。似然值Y(X,Y)   必须是0.0到1.0之间的浮点常数,包括0.0和1.0。似然(X)函数   是代码生成器优化掉的无操作,因此它不会消耗CPU周期   运行时(即,在调用sqlite3_step()期间)。可能性的目的(X,Y)   function是为查询规划器提供一个提示,即参数X是一个布尔值   大概为Y的概率为真。不太可能的(X)函数是短手的   似然性(X,0.0625)。

假设我知道1将返回75%的时间,那将会如何:

select likelihood(x,.75) 

帮助查询优化器?

1 个答案:

答案 0 :(得分:8)

original example是这样的:

  

考虑以下架构和查询:

CREATE TABLE composer(
  cid INTEGER PRIMARY KEY,
  cname TEXT
);
CREATE TABLE album(
  aid INTEGER PRIMARY KEY,
  aname TEXT
);
CREATE TABLE track(
  tid INTEGER PRIMARY KEY,
  cid INTEGER REFERENCES composer,
  aid INTEGER REFERENCES album,
  title TEXT
);
CREATE INDEX track_i1 ON track(cid);
CREATE INDEX track_i2 ON track(aid);

SELECT DISTINCT aname
  FROM album, composer, track
 WHERE cname LIKE '%bach%'
   AND composer.cid=track.cid
   AND album.aid=track.aid;
     

该模式适用于(简化的)音乐目录应用程序,但在其他情况下会出现类似的模式。有很多专辑。每个专辑包含一个或多个曲目。每首曲目都有一个作曲家。每个作曲家可能与多个曲目相关联。

     

查询会询问包含曲目的每张专辑的名称,该曲目的名称与'%bach%'匹配。

     

查询计划程序需要在此查询的几种备选算法中进行选择。最佳选择取决于表达式“cname LIKE'%bach%'”过滤结果的程度。让我们给这个表达式一个“过滤值”,这是一个介于1.0和0.0之间的数字。值为1.0表示对于composer表中的每一行,cname LIKE'%bach%'为true。值为0.0表示表达式永远不会为真。

     

当前的查询规划器(版本3.8.0)假定过滤器值为1.0。换句话说,它假定表达式始终为true。规划人员假设最坏的情况,以便选择一个最小化最坏情况运行时间的计划。这是一种安全的方法,但它不是最佳的。为1.0过滤器选择的计划是track-album-composer。这意味着“轨道”表位于外循环中。对于每一首曲目,在专辑上进行索引查找。然后在composer上进行索引查找,然后运行LIKE 表达式以查看是否应输出相册名称。

     

更好的计划是track-composer-album。如果LIKE 表达式为false,则第二个计划会避免相册查找。如果过滤器值略小于1.0,则当前规划器将选择第二种算法。说0.99。换句话说,如果规划器认为LIKE 表达式对于每100行中的1行是假的,那么它将选择第二个计划。这是过滤器值很大时的正确(最快)选择。

     

但是在音乐库的常见情况下,过滤器值可能比1.0更接近0.0。换句话说,在大多数作曲家名称中不太可能找到字符串“bach”。对于接近0.0的值,最好的计划是composer-track-album。作曲家 - 曲目 - 专辑计划是一旦查找匹配'%bach%'的条目就扫描作曲家表,并且每个匹配的条目使用索引来查找曲目然后查找专辑。当前的3.8.0查询计划器选择此当滤波器值小于约0.1时的第三个计划。

likelihood函数为数据库提供了(希望)对滤波器选择性的更好估计。 使用示例查询,它看起来像这样:

SELECT DISTINCT aname
  FROM album, composer, track
 WHERE likelihood(cname LIKE '%bach%', 0.05)
   AND composer.cid=track.cid
   AND album.aid=track.aid;