【问题标题】:How can I optimize VIEW or SELECT?如何优化 VIEW 或 SELECT?
【发布时间】:2018-05-10 02:09:42
【问题描述】:

我创建了名为 HistoriaTras 的视图,表示路线历史。

CREATE VIEW historiatras AS
SELECT
DataRozpoczeciaTrasy.deviceid AS deviceid,
DataZakonczeniaTrasy.ts - DataRozpoczeciaTrasy.ts AS RoznicaCzasu,
DataRozpoczeciaTrasy.ts AS RozpoczecieTrasy, DataZakonczeniaTrasy.ts AS ZakonczenieTrasy
FROM DEVICE_DATA DataRozpoczeciaTrasy
JOIN DEVICE_DATA DataZakonczeniaTrasy ON DataRozpoczeciaTrasy.deviceid = DataZakonczeniaTrasy.deviceid AND mod(DataZakonczeniaTrasy.inputs,2)=0 AND DataZakonczeniaTrasy.eventid = 11 AND DataZakonczeniaTrasy.ts > DataRozpoczeciaTrasy.ts
WHERE mod(DataRozpoczeciaTrasy.inputs,2)=1
AND DataRozpoczeciaTrasy.eventid = 11

ts = 时间戳
DataRozpoczeciaTrasy = 开始路线的日期
DataZakonczeniaTrasy = 停止路线的日期
RoznicaCzasu = DataRozpoczeciaTrasy - DataZakonczeniaTrasy

之间的时间 如果我在下面 SELECT 一切工作几乎都很好,但它需要太多时间 ~ 27 秒 - 而且它不包含所有路线(因为我从一天中选择一个设备 - 85758):

SELECT * FROM HistoriaTras Trasy
WHERE RoznicaCzasu = (SELECT MIN(Trasy1.RoznicaCzasu) 
                      FROM HistoriaTras Trasy1
                      WHERE Trasy.RozpoczecieTrasy = Trasy1.RozpoczecieTrasy) 
   AND deviceid = 85758 
   AND RozpoczecieTrasy > '2017-11-05 00:00:00' 
   AND RozpoczecieTrasy < '2017-11-06 00:00:00'

如果我删除:

AND deviceid = 85758 AND RozpoczecieTrasy > '2017-11-05 00:00:00' AND RozpoczecieTrasy < '2017-11-06 00:00:00'

这将花费...太多时间。我没有测试它,但它需要太长时间。

我在 device_data 表中有大约 100 k 行。 朋友,请写信给我如何优化这个选择或视图?我正在使用 PostgreSQL 10。

我正在粘贴 SELECT 的解释分析,因为不允许分析 VIEW:

Nested Loop  (cost=0.00..21281.66 rows=1 width=40) (actual time=3973.445..982716.756 rows=380 loops=1)
  Join Filter: ((datazakonczeniatrasy.ts > datarozpoczeciatrasy.ts) AND (datarozpoczeciatrasy.deviceid = datazakonczeniatrasy.deviceid) AND ((datazakonczeniatrasy.ts - datarozpoczeciatrasy.ts) = (SubPlan 1)))
  Rows Removed by Join Filter: 142880
  ->  Seq Scan on device_data datarozpoczeciatrasy  (cost=0.00..5259.22 rows=1 width=16) (actual time=0.046..17.667 rows=380 loops=1)
        Filter: ((eventid = '11'::numeric) AND (mod(inputs, '2'::numeric) = '1'::numeric))
        Rows Removed by Filter: 97518
  ->  Seq Scan on device_data datazakonczeniatrasy  (cost=0.00..5259.22 rows=1 width=16) (actual time=0.011..17.850 rows=377 loops=380)
        Filter: ((eventid = '11'::numeric) AND (mod(inputs, '2'::numeric) = '0'::numeric))
        Rows Removed by Filter: 97521
  SubPlan 1
    ->  Aggregate  (cost=10763.19..10763.20 rows=1 width=16) (actual time=34.834..34.834 rows=1 loops=28011)
          ->  Nested Loop  (cost=0.00..10763.19 rows=1 width=16) (actual time=9.246..34.805 rows=112 loops=28011)
                Join Filter: ((datazakonczeniatrasy_1.ts > datarozpoczeciatrasy_1.ts) AND (datarozpoczeciatrasy_1.deviceid = datazakonczeniatrasy_1.deviceid))
                Rows Removed by Join Filter: 270
                ->  Seq Scan on device_data datarozpoczeciatrasy_1  (cost=0.00..5503.96 rows=1 width=16) (actual time=5.930..17.172 rows=1 loops=28011)
                      Filter: ((eventid = '11'::numeric) AND (datarozpoczeciatrasy.ts = ts) AND (mod(inputs, '2'::numeric) = '1'::numeric))
                      Rows Removed by Filter: 97897
                ->  Seq Scan on device_data datazakonczeniatrasy_1  (cost=0.00..5259.22 rows=1 width=16) (actual time=0.012..17.327 rows=377 loops=28407)
                      Filter: ((eventid = '11'::numeric) AND (mod(inputs, '2'::numeric) = '0'::numeric))
                      Rows Removed by Filter: 97521
Planning time: 0.699 ms
Execution time: 982717.118 ms

我的桌子:

CREATE TABLE "public"."device_data" ( 
 "deviceid" Bigint REFERENCES cars (deviceid),
 "ts" Timestamp Without Time Zone,
 "longitude" Double Precision,
 "lattitude" Double Precision,
 "speedgps" Numeric( 5, 0 ),
 "heading" Numeric( 5, 0 ),
 "altitude" Numeric( 5, 0 ),
 "satelite" Numeric( 3, 0 ),
 "eventid" Numeric( 3, 0 ),
 "mileagegps" Numeric( 20, 0 ),
 "inputs" Numeric( 5, 0 ),
 "voltageanalog1" Numeric( 4, 2 ),
 "voltageanalog2" Numeric( 4, 2 ),
 "voltageanalog3" Numeric( 4, 2 ),
 "voltageanalog4" Numeric( 4, 2 ),
 "voltageanalog5" Numeric( 4, 2 ),
 "outputs" Numeric( 3, 0 ),
 "totaldistance" Numeric( 20, 0 ),
 "totalfuel" Numeric( 20, 0 ),
 "vehiclespeed" Numeric( 5, 0 ),
 "enginespeed" Numeric( 5, 0 ),
 "fuellevel" Numeric( 5, 0 ),
 "fuelcons" Numeric( 5, 0 ),
 "accelerator" Numeric( 3, 0 ),
 "tachograph" Numeric( 5, 0 ),
 "axleweight" Numeric( 5, 0 ),
 "indicators" Numeric( 10, 0 ),
 "drivercode" Numeric( 20, 0 ),
 "wiretemp1" Double Precision,
 "wiretemp2" Double Precision,
 "wiretemp3" Double Precision,
 "wiretemp4" Double Precision,
 "wiretemp5" Double Precision,
 "wiretemp6" Double Precision,
 "fuelflag" Integer,
 "gsmsignal" SmallInt,
 "speedcan" Integer,
 "gsmoperator" Bigint,
 "totalidlefuel" Bigint,
 "fuellevelperc" Integer,
 "enginetemp" SmallInt,
 "enginetotalhours" Bigint,
 "engineidletime" Bigint,
 "oiltemp" SmallInt,
 "hydroiltemp" SmallInt,
 "wirecode1" Numeric( 20, 0 ),
 "wirecode2" Numeric( 20, 0 ),
 "wirecode3" Numeric( 20, 0 ),
 "wirecode4" Numeric( 20, 0 ),
 "wirecode5" Numeric( 20, 0 ),
 "wirecode6" Numeric( 20, 0 ),
 "rapidpedalpress" Bigint,
 "rapidaccel" Bigint,
 "rapidbreak" Bigint,
 "engineoverspeed" Bigint,
 "torgue" SmallInt,
 "drivetimeoverspeedlimit0x12" Bigint,
 "drivetimeoverspeedlimit0x13" Bigint,
 "driver1idcard" Numeric( 20, 0 ),
 "driver2idcard" Numeric( 20, 0 ),
 "x3d" SmallInt,
 "y3d" SmallInt,
 "z3d" SmallInt,
 "axleweight1" Integer,
 "axleweight2" Integer,
 "axleweight3" Integer,
 "axleweight4" Integer );

【问题讨论】:

  • 运行analyze HistoriaTras;。然后运行explain analyze your_query,并将其输出粘贴到您的问题中。还要阅读 postgresql 性能标签中的info link
  • 感谢您提供的信息。我已经粘贴了 SELECT 的分析,因为它是虚拟表,所以不允许 VIEW 的分析。
  • 你绝对可以根据一个视图为一个select生成执行计划(但不会有什么不同)
  • 没有任何索引使用,你能发布你的表结构以及你有什么索引吗?
  • 那张表上有索引吗?见stackoverflow.com/questions/37329561/…

标签: postgresql optimization postgresql-performance


【解决方案1】:

我建议使用“窗口函数”LEAD() 而不是涉及使用MOD() 的自连接。

SELECT
      d.deviceid       AS deviceid
    , d.ts - d.lead_ts AS roznicaczasu
    , d.ts             AS rozpoczecietrasy
    , d.lead_ts        AS zakonczenietrasy
FROM (
      SELECT
            deviceid
          , ts
          , case when MOD(Inputs,2) = 1
                 then LEAD(ts) OVER (PARTITION BY deviceid, eventid 
                                     ORDER BY inputs DESC)
            end AS lead_ts
      FROM DEVICE_DATA
      WHERE eventid = 11
      ) d
WHERE d.lead_ts IS NOT NULL
;

【讨论】:

  • 你的建议工作几乎很好,但现在我看到在少数情况下,开始路线的日期晚于停止路线的日期:imgur.com/a/K8n3P 路线的开始时间是 eventid = 11 并且输入 mod 2 返回 1 . 当 eventid = 11 并且输入 mod 2 返回 0 时,路线停止。
  • 在上面的查询中试试这个ORDER BY MOD(Inputs,2) DESC 而不是ORDER BY Inputs因为我看不到任何数据,所以我蒙着眼睛工作
  • 感谢您提供的信息,但我仍然有错误的停止路线日期。请看图片:imgur.com/a/7tfmn 我在上面插入了一个例子。您选择检测到的路线停靠点,我将其标记为蓝色“您的停靠点”,但我想获得接近红色“停靠点”的日期。检测路线的开始是好的。 :)
  • 反转计算以避免负面影响,例如a-b = -?所以 b-a = +?
  • 我无法使用“数据图像”抱歉,它对我没用
猜你喜欢
  • 2016-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-31
  • 1970-01-01
  • 2011-12-01
  • 2013-01-03
相关资源
最近更新 更多