explain analyze SELECT COUNT(*) FROM "customers" WHERE (TRIM(telephone) =
'06868787878' AND check_id = 41);
QUERY PLAN
------------------------------------------------------------------------------
-------------------------------------------------------------------
Aggregate (cost=12982.58..12982.59 rows=1 width=0) (actual
time=200.452..200.453 rows=1 loops=1)
-> Bitmap Heap Scan on customers (cost=544.59..12982.21 rows=147 width=0)
(actual time=14.555..200.447 rows=1 loops=1)
Recheck Cond: (check_id = 41)
Filter: (btrim((telephone)::text) = '06868787878'::text)
Rows Removed by Filter: 29394
-> Bitmap Index Scan on idx_customers_check_id (cost=0.00..544.55
rows=29350 width=0) (actual time=9.669..9.669 rows=29395 loops=1)
Index Cond: (check_id = 41)
Total runtime: 200.750 ms
(8 rows)
有时它的服用(293.6ms),(1956.3ms),有什么方法可以避免这种情况吗?
答案 0 :(得分:1)
这在很大程度上取决于您的架构和使用模式,但有几点需要尝试。
TRIM
时,数据库必须在它正在评估的每一行上运行它,这很浪费。如果您保证您的号码始终被修剪,您可以进行更简单的telephone = '06868787878'
检查。如果这很常见,请确保telephone
上有索引。telephone
数据,create an index on the expression TRIM(telephone)
。这有效地预先计算了TRIM
正在进行的所有工作,但显然只是查找TRIM(telephone) = '123'
,而不是telephone = '123'
。{/ li>
将索引放在最具体的列上。例如。如果check_id
只有2行中的41
,Postgres可以先使用该索引缩小集合范围,然后只需要很少的工作来验证其余的条件。如果check_id
通常是41
,但telephone
很少06868787878
,则同样适用,您的索引应该在telephone
。如果两者都是相当均匀分布的并且这是一种常见的查询模式,那么您可能希望在(check_id, telephone)
上使用multicolumn index。遵循与单列索引相同的推理,将更具体的列放在第一位,或者如果您还需要仅对其中一列进行过滤,请先将其放在第一列。例如。 (check_id, telephone)
索引可让您有效地查询check_id
前缀。
3B。创建涵盖所有条件的多列索引可能非常有效,因为Postgres只能使用索引来执行计数,而无需执行辅助查找来获取主记录并检查索引未涵盖的条件。