bnu*_*sey 9 postgresql performance configuration index-tuning query-performance
这是查询:
SELECT "products".*
FROM "products"
WHERE (status > 100)
AND "products"."above_revenue_average" = 't'
AND ("products"."category_id" NOT IN (5))
ORDER BY "products"."start_date" DESC
Run Code Online (Sandbox Code Playgroud)
我在status和上有一个索引start_date。
每次从我的应用程序运行查询时,我都会在日志中得到以下信息:
SELECT "products".*
FROM "products"
WHERE (status > 100)
AND "products"."above_revenue_average" = 't'
AND ("products"."category_id" NOT IN (5))
ORDER BY "products"."start_date" DESC
Run Code Online (Sandbox Code Playgroud)
我相信这个临时文件的创建是性能缓慢的原因。
运行一个EXPLAIN ANALYZE我得到以下结果:
[WHITE] temporary file:
path "pg_tblspc/16386/PG_9.3_201306121/pgsql_tmp/pgsql_tmp2544.0", size 37093376
Query: SELECT "products".* FROM "products" WHERE (status > 100)
AND "products"."above_revenue_average" = 't'
AND ("products"."category_id" NOT IN (5)) ORDER BY "products"."start_date" DESC
Run Code Online (Sandbox Code Playgroud)
然后我使用http://explain.depesz.com/使其更具可读性:
QUERY PLAN
Sort (cost=63395.28..63403.51 rows=16460 width=524)
(actual time=524.134..562.635 rows=65294 loops=1)
Sort Key: start_date
Sort Method: external merge Disk: 36224kB
-> Bitmap Heap Scan on products
(cost=4803.40..60389.73 rows=16460 width=524)
(actual time=27.390..397.879 rows=65294 loops=1)
Recheck Cond: (status > 100)
Filter: (above_revenue_average AND (category_id <> 5))
Rows Removed by Filter: 25115
-> Bitmap Index Scan on index_products_on_status
(cost=0.00..4802.58 rows=89662 width=0)
(actual time=18.006..18.006 rows=90411 loops=1)
Index Cond: (status > 100)
Total runtime: 577.870 ms
(10 rows)
Run Code Online (Sandbox Code Playgroud)
+-------------------+-------+--------------+------------+
| node type | count | sum of times | % of query |
+-------------------+-------+--------------+------------+
| Bitmap Heap Scan | 1 | 379.873 ms | 67.5 % |
| Bitmap Index Scan | 1 | 18.006 ms | 3.2 % |
| Sort | 1 | 164.756 ms | 29.3 % |
+-------------------+-------+--------------+------------+
Run Code Online (Sandbox Code Playgroud)
我可以通过添加更多索引来提高数据库性能吗?也许一些复合的?有任何想法吗?
work_mem显然,排序操作会溢出到磁盘:
Run Code Online (Sandbox Code Playgroud)Sort Method: external merge Disk: 36224kB
更多work_mem可以帮助查询,就像@Kassandry 已经建议的那样。增加设置,直到您在输出中看到Memory代替。但根据一个查询增加常规设置可能不是一个好主意。正确的设置取决于可用的 RAM 和您的整体情况。首先阅读Postgres Wiki。DiskEXPLAIN
要修复您的查询,请仅在同一事务work_mem中为您的事务设置足够高的值。SET LOCAL
BEGIN;
SET LOCAL work_mem = '45MB';
SELECT ...
COMMIT; -- or ROLLBACK
Run Code Online (Sandbox Code Playgroud)
您可能需要 40 MB 多一点。内存中的表示比磁盘上的表示要大一些。有关的:
您的查询(消除一些噪音后):
SELECT *
FROM products
WHERE status > 100
AND above_revenue_average -- boolean can be used directly
AND category_id <> 5
ORDER BY start_date DESC;
Run Code Online (Sandbox Code Playgroud)
您的行宽为半千字节 ( width=524)。您需要返回所有列吗?(通常情况下,您不需要。)仅在SELECT列表中列出查询中需要的列,以提高整体性能,尤其是在您work_mem已经遇到问题的情况下。
所涉及的任何列都可以为 NULL 吗?category_id对于和尤为重要start_date。在这种情况下你可能想要适应......
多列索引当然可以提高性能。(就像@Paul 概述的那样)。你必须权衡成本和收益。如果此查询的性能很重要或者很常见,那就去做吧。不要为每个查询创建特殊索引。尽可能少,必要时多。共享索引时功能更强大,这增加了更多索引保留在缓存中的机会。
像这样的boolean列above_revenue_average是部分索引中条件的典型候选者,而不是索引列。
根据不完整的信息我的疯狂猜测:
CREATE INDEX prod_special_idx ON products (start_date DESC)
WHERE above_revenue_average
AND status > 100
AND category_id <> 5;
Run Code Online (Sandbox Code Playgroud)
如果可以为 NULL,DESC NULLS LAST则在索引和查询中使用。start_date
| 归档时间: |
|
| 查看次数: |
8802 次 |
| 最近记录: |