为什么不走索引, PostgreSQL

原文出处:
">http://www.postgresonline.com/journal/archives/78-why-si-my-index-not-being-used.html>
有一个老的问题经常会问道数据库转件就是为什么或者为什么表的索引没有被使用?
下面的文章将会简单的回答这个常见的问题,并按着统计学意义排序。

一、对于外行人来说,你怎么知道索引没有被使用呢?
可以使用 EXPLAIN ; EXPLAIN ANALYZE 或者 pgadmin 的图形执行计划来查看。 ">http://www.postgresonline.com/journal/archives/27-Reading-PgAdmin-Graphical-Explain-Plans.html>
如果查询语句确实没有走索引,那么我们应该怎么做呢?

  1. 原因: 过时的统计信息。如果你的数据库 auto-vacuum 选项是打开的, 那么就不会引起这个问题的发生。但是如果你最近刚批量的导入数据,且新建了索引,那么很有可能,统计信息过期,导致查询优化器不能获得最新的统计信息,做出正确的判断。
    方案: vacuum analyze verbose sometable_name;

这里增加了 verbose 参数,是因为它可以使你看的更清晰 vacuum 是如何运作的。

  1. 原因: 查询优化器认为选择 table scan 要比选择 index scan 更快: 做出这种选择的原因是,查询涉及的表太小了, 或者我们构建索引的字段重复值太多。

    方案: 对于 布尔字段构建索引可以认为不是很重要,因为一半是数据,另一半也是数据。不过对这种字段构建部分索引是最好的选择,值索引活动的数据。
    
  2. 构建的索引与实际过滤字段的方式不兼容。这里有很多种解决方法
    3.1 LIKE %me 将永远不会选择索引扫描, 但是 LIKE me% 就有可能选择索引扫描

3.2 大小写的陷阱,例子如下

<pre><code>
 CREATE INDEX idx_faults_name ON faults USING btree (fault_name);     --- 构建的索引
 --- 查询语句如下
 SELECT * FROM faults WHERE UPPER(FAULT_NAME) LIKE 'CAR%' Possible fix;
--- 解决办法如下
 CREATE INDEX idx_faults_name ON faults  USING BTREE (upper(fault_name));
</code></pre>

3.3 这个问题很难被意识到, 通过阅读别人的问题,你就会更好的发现问题。这个问题涉及到了 运算符类

  <https://www.postgresql.org/message-id/49075E5E.6040701@gmail.com> 知道这个问题的解决方法的人很少


The other point is that in non-C locales, a standard varchar index isn't

usable for LIKE (the sort order is usually wrong). You can re-initdb
in C locale or create a varchar_pattern_ops index.
booktown=# create index first_name_idx_vpo on auth using btree

(first_name varchar_pattern_ops);

)
  解决方案如下:
  <pre><code>
  CREATE INDEX idx_faults_uname_varcahr_parttern on faluts USING BTREE (UPPER (fault_name) varchar_parttern_ops);
  </code></pre>
 看到这个解决方案,可能还需要下面的变体和 *IN* 子句才能解决问题。
 我们并不能证明这是数据库编码的问题, 数据的不同或者数据库版本的不同。 8。2 , 8.3 。 对于pg8.3 我们推荐使用 *UTF-8* 的编码方式初始化数据库。而对于 8.2 版本是使用的 *SQL-ASCII*, 这个参数 *varcahr_pattern_ops* 对于 *like* 语句是足够解决的。
  <pre><code>
  CREATE INDEX idx_faults_uname ON faults USING btree (upper (falut_name));

 SELECT fault_name from faults WHERE upper(fault_name) IN ( 'CASCADIA ABDUCTION', 'CABIN FEVER');
 </code></pre>
3.4  不兼容的数据类型。
       例如, 我们为日期类型构建索引,但是却通过将日期类型转换为 text 类型, 用在比较语句中, 是不选索引扫描的。
  1. 并不是所有的索引都会被使用。 尽管 pg8.1以上的版本开始支持 Bitmap Index scan. 该索引扫描允许一个表上构建多个索引, 在查询执行时,将这些索引构建为 内存位图的形式。 如果你构建了很多索引, 不要期望全部候选索引都会被用到。有些时候,执行 table scan 会更高效。

    1. 问题: 查询优化器的不完美。

      方案: 期待更美好的查询优化器的产生。 事实上, postgresql 优化器的能力很不错的。*If only I could provide hints, I could make this faster *.最好的解决方案就是让查询优化器变的更好。随着数据库的变化, 优化器也随之变化, 这就是数据库编程不同于其他编程的原因。
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
如果您的PostgreSQL表的主键不使用索引进行查询,可能有以下几个原因: 1. 索引未创建或已损坏:请确保已在主键列上创建了索引,并且该索引正常工作。您可以使用以下命令检查索引是否存在: ``` \d table_name ``` 如果索引未显示,请使用以下命令在主键列上创建索引: ``` CREATE INDEX index_name ON table_name (primary_key_column); ``` 2. 数据不均匀:如果表中的数据分布不均匀,则可能会导致索引不起作用。例如,如果表中有大量重复的值,则索引可能会失效。在这种情况States.size(); i++) { if (dfaStates[i].lr0Items.size() == lr0Items.size()) { bool isSame = true; for (int j = 0; j < lr0Items.size(); j++) { LR0Item item1 = lr0Items[j]; LR0Item item2 = dfaStates[i].lr0Items[j]; if (item1.productionIndex != item2.productionIndex || item1.dot != item2.dot) { isSame = false; break; } } if (isSame) { return i; } } } return -1; } ``` 4. 进行语法分析 在SLR(1)分析中,需要使用栈来保存DFA状态编号和符号。可以使用一个结构体来表示栈: ``` struct StackItem { int stateIndex; // DFA状态编号 char symbol; // 符号 }; ``` 可以使用一个vector来表示栈: ``` vector<StackItem> stack; ``` 在分析过程中,需要读入一个输入字符串,并将其转换为一个字符数组。然后,从栈中取出当前状态,并读入下一个字符,根据ACTION和GOTO分析表中的项进行相应的操作。 - 如果ACTION[s][a]为"shift j",则将j推入栈中,并将输入字符指针后移一位。 - 如果ACTION[s][a]为"reduce A -> α",则从栈中弹出|α|个状态和符号,将A推入栈中,并将GOTO[top()][A]推入栈中。 - 如果ACTION[s][a]为"accept",则分析成功。 - 如果ACTION[s][a]为"error",则分析失败。 可以通过以下代码来实现语法分析的过程: ``` stack.push_back(StackItem{0, '#'}); int i = 0; while (i < strlen(input)) { int s = stack.back().stateIndex; char a = input[i]; if (actionTable[s][(int)a].action == 's') { // Shift int j = actionTable[s][(int)a].nextState; stack.push_back(StackItem{j, a}); i++; } else if (actionTable[s][(int)a].action == 'r') { // Reduce int reduceProductionIndex = actionTable[s][(int)a].nextState; Production production = productions[reduceProductionIndex]; int alphaLength = production.right.length(); vector<StackItem> poppedItems(alphaLength); for (int j = 0; j < alphaLength; j++) { poppedItems[j] = stack.back(); stack.pop_back(); } reverse(poppedItems.begin(), poppedItems.end()); int t = stack.back().stateIndex;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值