【发布时间】:2015-01-18 04:29:58
【问题描述】:
我有一个问题:
EXPLAIN ANALYZE
SELECT CAST(DATE(associationtime) AS text) AS date ,
cast(SUM(extract(epoch
FROM disassociationtime) - extract(epoch
FROM associationtime)) AS bigint) AS sessionduration,
cast(SUM(tx) AS bigint)AS tx,
cast(SUM(rx) AS bigint) AS rx,
cast(SUM(dataRetries) AS bigint) AS DATA,
cast(SUM(rtsRetries) AS bigint) AS rts,
count(*)
FROM SESSION
WHERE ssid_id=42
AND ap_id=1731
AND DATE(associationtime)>=DATE('Tue Nov 04 00:00:00 MSK 2014')
AND DATE(associationtime)<=DATE('Thu Nov 20 00:00:00 MSK 2014')
GROUP BY(DATE(associationtime))
ORDER BY DATE(associationtime);
输出是:
GroupAggregate (cost=0.44..17710.66 rows=1 width=32) (actual time=4.501..78.880 rows=17 loops=1)
-> Index Scan using session_lim_values_idx on session (cost=0.44..17538.94 rows=6868 width=32) (actual time=0.074..73.266 rows=7869 loops=1)
Index Cond: ((date(associationtime) >= '2014-11-04'::date) AND (date(associationtime) <= '2014-11-20'::date))
Filter: ((ssid_id = 42) AND (ap_id = 1731))
Rows Removed by Filter: 297425
Total runtime: 78.932 ms
看看这一行:
Index Scan using session_lim_values_idx
如您所见,查询使用三个字段进行扫描:ssid_id、ap_id 和关联时间。我有一个索引:
ssid_pkey | btree | {id}
ap_pkey | btree | {id}
testingshit_pkey | btree | {one,two,three}
session_date_ssid_idx | btree | {ssid_id,date(associationtime),"date_trunc('hour'::text, associationtime)"}
session_pkey | btree | {associationtime,disassociationtime,sessionduration,clientip,clientmac,devicename,tx,rx,protocol,snr,rssi,dataretries,rtsretries }
session_main_idx | btree | {ssid_id,ap_id,associationtime,disassociationtime,sessionduration,clientip,clientmac,devicename,tx,rx,protocol,snr,rssi,dataretres,rtsretries}
session_date_idx | btree | {date(associationtime),"date_trunc('hour'::text, associationtime)"}
session_date_apid_idx | btree | {ap_id,date(associationtime),"date_trunc('hour'::text, associationtime)"}
session_date_ssid_apid_idx | btree | {ssid_id,ap_id,date(associationtime),"date_trunc('hour'::text, associationtime)"}
ap_apname_idx | btree | {apname}
users_pkey | btree | {username}
user_roles_pkey | btree | {user_role_id}
session_lim_values_idx | btree | {date(associationtime)}
它叫做session_date_ssid_apid_idx。但是为什么查询使用错误的索引?
session_date_ssid_apid_idx:
------------+-----------------------------+-------------------------------------------
ssid_id | integer | ssid_id
ap_id | integer | ap_id
date | date | date(associationtime)
date_trunc | timestamp without time zone | date_trunc('hour'::text, associationtime)
session_lim_values_idx:
date | date | date(associationtime)
你会创建什么索引?
UPD: \d session
--------------------+-----------------------------+------------------------------------------------------
id | integer | NOT NULL DEFAULT nextval('session_id_seq'::regclass)
ssid_id | integer | NOT NULL
ap_id | integer | NOT NULL
associationtime | timestamp without time zone | NOT NULL
disassociationtime | timestamp without time zone | NOT NULL
sessionduration | character varying(100) | NOT NULL
clientip | character varying(100) | NOT NULL
clientmac | character varying(100) | NOT NULL
devicename | character varying(100) | NOT NULL
tx | integer | NOT NULL
rx | integer | NOT NULL
protocol | character varying(100) | NOT NULL
snr | integer | NOT NULL
rssi | integer | NOT NULL
dataretries | integer | NOT NULL
rtsretries | integer | NOT NULL
╚эфхъё√:
"session_pkey" PRIMARY KEY, btree (associationtime, disassociationtime, sessionduration, clientip, clientmac, devicename, tx, rx, protocol, snr, rssi, dataretries, rtsretries)
"session_date_ap_ssid_idx" btree (ssid_id, ap_id, associationtime)
"session_date_apid_idx" btree (ap_id, date(associationtime), date_trunc('hour'::text, associationtime))
"session_date_idx" btree (date(associationtime), date_trunc('hour'::text, associationtime))
"session_date_ssid_apid_idx" btree (ssid_id, ap_id, associationtime)
"session_date_ssid_idx" btree (ssid_id, date(associationtime), date_trunc('hour'::text, associationtime))
"session_lim_values_idx" btree (date(associationtime))
"session_main_idx" btree (ssid_id, ap_id, associationtime, disassociationtime, sessionduration, clientip, clientmac, devicename, tx, rx, protocol, snr, rssi, dataretries, rtsretries)
【问题讨论】:
-
这真的是执行计划的完整输出吗?我希望其中至少有另一个步骤来查找其他列。顺便说一句:您可以删除以下索引之一:
ssid_pkey或ap_pkey它们是相同的。最好显示 psql 的\d命令输出的索引列表,而不是系统目录的(有点混乱)内容(或至少使用视图pg_indexes) -
从我目前看到的情况来看,应该使用索引
session_date_ssid_apid_idx。您的问题中缺少某些内容,或者您的数据库有问题。我会删除该索引(或所有索引),运行VACUUM FULL ANALYZE session,重新创建索引(或所有索引)并重试。或者如果您无法锁定表,请使用pg_repack。 或者您的大多数列都有ssid_id=42 AND ap_id=1731,因此这些谓词对于索引的选择无关紧要,使用较小的索引并过滤其余的索引会更便宜。 -
@ErwinBrandstetter,看来您对
ssid_id=42 AND ap_id=1731的看法是正确的。如果我将这些值更改为不太受欢迎,则会选择新索引(右索引)。 -
SELECT count(*) AS a, count(ssid_id=42 AND ap_id=1731 OR NULL) AS b FROM session能得到什么? -
对于
SELECT count(associationtime BETWEEN '2014-11-04 0:0' AND '2014-11-20 0:0' OR NULL) AS a, count(associationtime BETWEEN '2014-11-04 0:0' AND '2014-11-20 0:0' AND ssid_id=42 AND ap_id=1731 OR NULL) AS b FROM session?
标签: postgresql indexing postgresql-performance sql-execution-plan