`
楚若之夜
  • 浏览: 121564 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

MINUS,外连接,NOT IN,NOT EXISTS 的效率比较

 
阅读更多

关于 MINUS,外连接,NOT IN,NOT EXISTS 的效率比较,绝对是一个很老很老的话题了.

如果要完成这个需求:"取出一些记录,在表A中,不在表B中", 你会采用哪种方案?为什么会采用这种方案?

我作了一个实验, 发现随着数据库版本的不同,CBO的工作方式也有变化.

本文仅限于一般性的分析, 不涉及internal.

 

一.  概述
首先, 我必须纠正自己的一个"错误认识": MINUS的效率很低.
针对上面提到的需求,采用哪种查询方式,其效率取决于:

1.  两个表的数据量,以及数据分布;
2.  表有没有经过分析;
3.  子查询中是否包含NULL值 (很重要);
4.  是否存在索引;
5.  数据库版本:不同版本的数据库,优化器的工作方式会有差异.
二. 环境
首先测试的数据库的版本是Oracle 9.0.1.5,接下来我会在10G中也测试一下.

两个与优化器工作原理相关的的参数都用的是缺省值.


optimizer_index_caching
 integer 
 0
 
optimizer_index_cost_adj 
 integer 
 100
 


 

表T1,T2,结构相同,但是数据不同.T2可以看成是T1的子集.
表的结构很简单,都取自dba_objects视图
 

create table t1 as select * from dba_objects where rownum<=13000;

 

create table t2 as select * from dba_objects where rownum<=11000;

Create index ix_t2 on t2(object_id);

三. 测试
目标: 我想把T1表中其它的数据也导入到T2表.

方式: 启动SQL TRACE, 再用tkprof对生成的trace文件进行解析.

首先用 NOT IN来执行,

1. 使用 NOT IN
 select count(*) from t1 where object_id not in ( select object_id from t2);

 


call
 count
 cpu
 elapsed
 disk
 query
 current
 rows
 
Parse
 1
 0.00
 0.01
 0
 0
 0
 0
 
Execute
 1
 0.00
 0.00
 0
 0
 0
 0
 
Fetch
 2
 16.84
 18.05
 190
 1153542
 0
 1
 
total
 4
 16.84
 18.06
 190
 1153542
 0
 1
 


 


Rows
 Row Source Operation
 
1
 SORT AGGREGATE
 
2000
 FILTER
 
13000
 TABLE ACCESS FULL T1
 
11000  
 TABLE ACCESS FULL T2
 


结论: 两次全表扫描的代价显然太高了,无疑是效率最低的方案.
2. 使用MINUS 
 alter system flush shared_pool;
 alter session set sql_trace=true;
 Select count(*) from
     (select object_id from t1
       minus
      select object_id from t2
     );

alter session set sql_trace=false;

 


call
 count
 Cpu
 elapsed
 disk
 query
 current
 rows
 
Parse
 1
 0.01
 0.00
 0
 2
 0
 0
 
Execute
 1
 0.00
 0.00
 0
 0
 0
 0
 
Fetch
 2
 0.04
 0.03
 0
 356
 0
 1
 
total
 4
 0.05
 0.03
 0
 358
 0
 1
 


 


Rows
 Row Source Operation
 
1
 SORT AGGREGATE
 
2000
 VIEW
 
2000   
 MINUS
 
13000
 SORT UNIQUE
 
13000
 TABLE ACCESS FULL T1
 
11000 
 SORT UNIQUE
 
11000 
 TABLE ACCESS FULL T2
 


结论: 看上去效率很不错
3. 使用 not exists

 alter system flush shared_pool;
 alter session set sql_trace=true;
 select count(*)
      from t1
     where not exists
      (select null from t2 where t2.object_id = t1.object_id);

alter session set sql_trace=false;

 


call
 count
 Cpu
 elapsed
 disk
 query
 current
 rows
 
Parse
 1
 0.01
 0.00
 0
 2
 0
 0
 
Execute
 1
 0.00
 0.00
 0
 0
 0
 0
 
Fetch
 2
 0.08
 0.21
 24
 26197
 0
 1
 
total
 4
 0.09
 0.21
 24
 26199
 0
 1
 


 


Rows
 Row Source Operation
 
1
 SORT AGGREGATE
 
2000
 FILTER
 
13000
  TABLE ACCESS FULL T1
 
11000
 INDEX RANGE SCAN (object id 108538)
 


结论: 效率比NOT IN 好很多,但是不如MINUS,并且存在物理读.

4. 最后来看看我比较喜欢用的外连接(+)

 alter system flush shared_pool;
 alter session set sql_trace=true;
 select count(*)
      from t1, t2
     where t1.object_id = t2.object_id(+)
      and t2.object_id IS NULL;

alter session set sql_trace=false;

 


call
 count
 Cpu
 elapsed
 disk
 query
 current
 rows
 
Parse
 1
 0.01
 0.00
 0
 2
 0
 0
 
Execute
 1
 0.00
 0.00
 0
 0
 0
 0
 
Fetch
 2
 0.05
 0.05
 0
 13222
 0
 1
 
total
 4
 0.06
 0.05
 0
 13224
 0
 1
 


 


Rows
 Row Source Operation
 
1
 SORT AGGREGATE
 
2000
 FILTER
 
13000 
 NESTED LOOPS OUTER
 
13000
 TABLE ACCESS FULL T1
 
11000
 INDEX RANGE SCAN (object id 108538)
 


结论: 比NOT EXISTS的效果好,不如MINUS.从查询计划来看,显然不是一个最优计划.

四. 对表分析后再测试
analyze table t1 compute statistics;

1.     NOT IN

alter system flush shared_pool;
alter session set sql_trace=true;

select count(*)
from t1
where object_id not in (select object_id from t2);

alter session set sql_trace=false;

 


call
 count
 Cpu
 elapsed
 disk
 query
 current
 rows
 
Parse
 1
 0.02
 0.00
 0
 0
 0
 0
 
Execute
 1
 0.00
 0.00
 0
 0
 0
 0
 
Fetch
 2
 16.04
 0.05
 0
 0
 0
 1
 
total
 4
 16.06
 0.05
 0
 0
 0
 1
 


 


Rows
 Row Source Operation
 
1
 SORT AGGREGATE
 
2000
 FILTER
 
13000 
 TABLE ACCESS FULL T1
 
11000
 TABLE ACCESS FULL T2
 


结论:与分析前相比,没有任何改变
2.     MINUS

alter system flush shared_pool;
alter session set sql_trace=true;

Select count(*) from
  (select object_id from t1
     minus
   select object_id from t2
  );

alter session set sql_trace=false;

 


call
 count
 Cpu
 elapsed
 disk
 query
 current
 rows
 
Parse
 1
 0.00
 0.00
 0
 76
 0
 0
 
Execute
 1
 0.00
 0.00
 0
 0
 0
 0
 
Fetch
 2
 0.05
 0.04
 0
 356
 0
 1
 
total
 4
 0.05
 0.04
 0
 342
 0
 1
 


 


Rows
 Row Source Operation
 
1
 SORT AGGREGATE
 
2000
 VIEW
 
2000 
 MINUS
 
13000
 SORT UNIQUE
 
13000
 TABLE ACCESS FULL T1
 
11000
 SORT UNIQUE
 
11000
 TABLE ACCESS FULL T2
 


结论: 查询计划没有改变, 虽然各项指标有些不同.

3.     使用NOT EXISTS

alter system flush shared_pool;
alter session set sql_trace=true;

select count(*)
 from t1
  where not exists
   (select null from t2 where t2.object_id = t1.object_id);

alter session set sql_trace=false;

 


call
 count
 Cpu
 elapsed
 disk
 query
 current
 rows
 
Parse
 1
 0.01
 0.02
 0
 144
 0
 0
 
Execute
 1
 0.00
 0.00
 0
 0
 0
 0
 
Fetch
 2
 0.08
 0.08
 0
 26197
 0
 1
 
total
 4
 0.09
 0.10
 0
 26341
 0
 1
 


 


Rows
 Row Source Operation
 
1
 SORT AGGREGATE
 
2000
 FILTER
 
13000 
 TABLE ACCESS FULL T1
 
11000
 INDEX RANGE SCAN (object id 108538)
 


结论: 查询计划也没有改变.

4.     使用 外连接
alter system flush shared_pool;
alter session set sql_trace=true;

select count(*)
 from t1, t2
  where t1.object_id = t2.object_id(+)
   and t2.object_id IS NULL;

alter session set sql_trace=false;

 


call
 count
 Cpu
 elapsed
 disk
 query
 current
 rows
 
Parse
 1
 0.01
 0.00
 0
 1
 0
 0
 
Execute
 1
 0.00
 0.00
 0
 0
 0
 0
 
Fetch
 2
 0.02
 0.01
 0
 223
 0
 1
 
total
 4
 0.03
 0.01
 0
 224
 0
 1
 


 


Rows
 Row Source Operation
 
1
 SORT AGGREGATE
 
2000
 FILTER
 
13000 
 HASH JOIN OUTER
 
13000
 TABLE ACCESS FULL T1
 
11000
 INDEX FAST FULL SCAN (object id 108538)
 


结论: 经过分析以后,使用了HASH JOIN,效率提高很明显.这是一个正确的查询计划.

 

总结:这四种查询模式中使用外连接的效率最高.

五. 在10G中测试
T1: 10000
T2: 9800

NOT IN


call
 count
 Cpu
 elapsed
 disk
 query
 current
 rows
 
Parse
 1
 0.00
 0.00
 0
 0
 0
 0
 
Execute
 1
 0.00
 0.00
 0
 0
 0
 0
 
Fetch
 2
 7.65
 7.47
 135
 685810
 0
 1
 
total
 4
 7.65
 7.47
 135
 685810
 0
 1
 


执行计划:


Rows
 Row Source Operation
 
1
 SORT AGGREGATE (cr=685810 pr=135 pw=0 time=7479614 us)
 
200
 FILTER  (cr=685810 pr=135 pw=0 time=7474258 us)
 
10000 
 TABLE ACCESS FULL T1 (cr=138 pr=135 pw=0 time=40407 us)
 
9800
 TABLE ACCESS FULL T2 (cr=685672 pr=0 pw=0 time=7366891 us)
 


对T1进行分析后

call
 count
 Cpu
 elapsed
 disk
 query
 current
 rows
 
Parse
 1
 0.00
 0.01
 0
 3
 0
 0
 
Execute
 1
 0.00
 0.00
 0
 0
 0
 0
 
Fetch
 2
 0.01
 0.01
 22
 165
 0
 1
 
total
 4
 0.01
 0.02
 22
 168
 0
 1
 


执行计划:

Rows
 Row Source Operation
 
1
 SORT AGGREGATE (cr=165 pr=22 pw=0 time=15933 us)
 
200
 HASH JOIN ANTI (cr=165 pr=22 pw=0 time=15973 us)
 
10000 
 TABLE ACCESS FULL T1 (cr=138 pr=0 pw=0 time=10075 us)
 
9800
 INDEX FAST FULL SCAN IX_T2 (cr=27 pr=22 pw=0 time=10529 us)(object id 52081)
 


另外, 通过对NOT EXISTS的分析,发现它的效率要好于MINUS,这也是一个变化.

 

六. 结束语
从上面的对比分析,可以得出这样的结论:

10G的CBO要比9i的CBO智能了不少, 对于NOT IN 和NOT EXISTS 这两种使用频率较高的语句,能使用最优的查询计划.

分享到:
评论

相关推荐

    高分项目 基于STM32F103单片机的无线测距系统源代码+项目资料齐全+教程文档.zip

    【资源概览】 高分项目 基于STM32F103单片机的无线测距系统源代码+项目资料齐全+教程文档.zip高分项目 基于STM32F103单片机的无线测距系统源代码+项目资料齐全+教程文档.zip高分项目 基于STM32F103单片机的无线测距系统源代码+项目资料齐全+教程文档.zip 【资源说明】 高分项目源码:此资源是在校高分项目的完整源代码,经过导师的悉心指导与认可,答辩评审得分高达95分,项目的质量与深度有保障。 测试运行成功:所有的项目代码在上传前都经过了严格的测试,确保在功能上完全符合预期,您可以放心下载并使用。 适用人群广泛:该项目不仅适合计算机相关专业(如电子信息、物联网、通信工程、自动化等)的在校学生和老师,还可以作为毕业设计、课程设计、作业或项目初期立项的演示材料。对于希望进阶学习的小白来说,同样是一个极佳的学习资源。 代码灵活性高:如果您具备一定的编程基础,可以在此代码基础上进行个性化的修改,以实现更多功能。当然,直接用于毕业设计、课程设计或作业也是完全可行的。 欢迎下载,与我一起交流学习,共同进步!

    java八股文介绍00002

    java八股文,"Java八股文"通常指的是在面试Java开发者时经常被问到的一系列标准问题,这些问题往往是技术面试中的基础部分,用来评估应聘者对Java编程语言和Java虚拟机(JVM)的理解程度。这些问题的答案往往模式化,因此被称为“八股文”。虽然这个词汇带有一定的贬义,但是这些问题却是面试中不可或缺的一部分,因为它们能够快速地检验应聘者的基本技能和理论知识。

    东北大学本科毕业设计 论文latex模板 2019

    东北大学本科毕业设计 论文latex模板 2019 关于东北大学本科毕业设计论文的LaTeX模板,您可以参考以下两个资源: 1. **Acytoo/neu_bachelor_thesis_template**: 这个模板是修改自一位学长的模板,以适应东北大学最新的要求。它使用GBT7714-2005参考文献标准,并提供了详细的安装和使用说明。您需要使用xelatex进行编译,并可能需要手动安装参考文献的标准。此外,如果您使用的是VSCode编辑器,可以参考提供的VSCode配置。 2. **tzaiyang/NEUBachelorThesis**: 这个模板同样适用于东北大学本科生毕业论文。它提供了详细的VSCode配置,包括快捷键设置和texcount bug修复(仅限Windows用户)。此外,还提供了如何插入公式、图片和三线表的说明,以及如何引用参考文献的方法。 您可以根据自己的需求和喜好选择其中一个模板。如果您对LaTeX不熟悉,建议先学习一些基础知识,以便更好地使用这些模板。祝您毕业设计顺利!

    node-v7.2.0-linux-armv7l.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    串口通讯原理+硬件原理解释+软件配置

    STM32串口通信大纲---适用于初学者 I. 引言 学习背景与串口通信的重要性 简述本文目的与主要内容 II. STM32里的串口通信 基本概念与功能介绍 USART及STM32内置串口 全双工通信与异步时钟控制 接收/发送逻辑结构 III. 串口配置 选择合适的串口资源(USART1/2/3) 参数设置:波特率、位数、校验、停止位 GPIO配置:TX/RX引脚驱动方式 IV. 串口发送与接收 发送数据流程 设置TDR与发送移位寄存器 检测TXE标志位 数据移位与持续发送 接收数据流程 配置RX输入模式 读取RDR与RXNE标志 字节数据接收 V. 实现方式 不使用中断的简单示例 利用中断接收数据 查询中断状态 中断服务程序处理数据

    基于opencv和深度学习的手写计算器.zip

    基于opencv和深度学习的手写计算器.zip

    高分项目 基于STM32单片机和Android的智能蓝牙点餐系统源代码+项目资料齐全+教程文档.zip

    【资源概览】 高分项目 基于STM32单片机和Android的智能蓝牙点餐系统源代码+项目资料齐全+教程文档.zip高分项目 基于STM32单片机和Android的智能蓝牙点餐系统源代码+项目资料齐全+教程文档.zip高分项目 基于STM32单片机和Android的智能蓝牙点餐系统源代码+项目资料齐全+教程文档.zip 【资源说明】 高分项目源码:此资源是在校高分项目的完整源代码,经过导师的悉心指导与认可,答辩评审得分高达95分,项目的质量与深度有保障。 测试运行成功:所有的项目代码在上传前都经过了严格的测试,确保在功能上完全符合预期,您可以放心下载并使用。 适用人群广泛:该项目不仅适合计算机相关专业(如电子信息、物联网、通信工程、自动化等)的在校学生和老师,还可以作为毕业设计、课程设计、作业或项目初期立项的演示材料。对于希望进阶学习的小白来说,同样是一个极佳的学习资源。 代码灵活性高:如果您具备一定的编程基础,可以在此代码基础上进行个性化的修改,以实现更多功能。当然,直接用于毕业设计、课程设计或作业也是完全可行的。 欢迎下载,与我一起交流学习,共同进步!

    高分项目 基于STM32单片机的桌面电磁力时钟摆设计源代码+项目资料齐全+教程文档.zip

    【资源概览】 高分项目 基于STM32单片机的桌面电磁力时钟摆设计源代码+项目资料齐全+教程文档.zip高分项目 基于STM32单片机的桌面电磁力时钟摆设计源代码+项目资料齐全+教程文档.zip高分项目 基于STM32单片机的桌面电磁力时钟摆设计源代码+项目资料齐全+教程文档.zip 【资源说明】 高分项目源码:此资源是在校高分项目的完整源代码,经过导师的悉心指导与认可,答辩评审得分高达95分,项目的质量与深度有保障。 测试运行成功:所有的项目代码在上传前都经过了严格的测试,确保在功能上完全符合预期,您可以放心下载并使用。 适用人群广泛:该项目不仅适合计算机相关专业(如电子信息、物联网、通信工程、自动化等)的在校学生和老师,还可以作为毕业设计、课程设计、作业或项目初期立项的演示材料。对于希望进阶学习的小白来说,同样是一个极佳的学习资源。 代码灵活性高:如果您具备一定的编程基础,可以在此代码基础上进行个性化的修改,以实现更多功能。当然,直接用于毕业设计、课程设计或作业也是完全可行的。 欢迎下载,与我一起交流学习,共同进步!

    node-v7.9.0-linux-ppc64le.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    基于深度学习的手写数字识别.zip

    基于深度学习的手写数字识别.zip

    Parameter-Free Fast Pixelwise Non-Local Means Denoising

    这篇文章的核心内容是关于一种图像去噪算法——非局部均值(Non-Local Means, NLM)算法的快速且开源的实现。以下是文章的主要要点: 算法介绍:文章提出了一种快速且无参数的NLM算法实现,该算法用于去除图像中的噪声。NLM算法由Antoni Buades, Bartomeu Coll和Jean-Michel Morel在2005年引入,因其简单性、出色的视觉效果以及利用自然图像的非局部冗余性而受到广泛欢迎。 算法改进:文章基于线之和的计算来计算块距离,这些线在块移位下是不变的。通过从一个图像数据库中计算NLM的最佳参数(以平均峰值信噪比PSNR为标准),实现了一个无需参数调整的NLM算法。

    Hypack 2016、Hypack 2021、Hypack 2022、Hypack 2024 完整中文资源

    Hypack 2016、Hypack 2021、Hypack 2022、Hypack 2024 四个版本的完整中文资源,全部完成汉化,汉化完整错误少,全网汉化第一,替换相应版本的资源文件即可。 压缩包含资源文件lngEdit.db和汉化了的lngEdit.exe程序(命名为lngEditChs.exe)

    selenium 库和浏览器驱动的安装.rar

    selenium 库和浏览器驱动的安装.rar

    预警系统链性态网体系化作战矩阵.txt

    预警系统链性态网体系化作战矩阵.txt

    基于深度学习的普通话语音识别.zip

    基于深度学习的普通话语音识别.zip

    node-v7.1.0-sunos-x86.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    com.smile.gifmaker.apk

    com.smile.gifmaker.apk

    改进模拟退火算法模型中英文版.vsdx

    模拟退火算法(Simulated Annealing,SA)是一种基于概率的算法,其灵感来源于固体退火原理。模拟退火算法最早由N. Metropolis等人在1953年提出,随后在1983年由S. Kirkpatrick等人成功地将退火思想引入到组合优化领域。该算法基于物理中固体物质的退火过程与一般组合优化问题之间的相似性,通过赋予搜索过程一种时变且最终趋于零的概率突跳性,从而有效避免陷入局部极小并最终趋于全局最优。 模拟退火算法的基本思想是从某一较高初温出发,伴随温度参数的不断下降,结合概率突跳特性在解空间中随机寻找目标函数的全局最优解。算法的主要步骤如下: 初始化:设置初始温度T(充分大)、初始解状态S(算法迭代的起点)以及每个T值的迭代次数L。 对k=1,...,L进行以下操作: 产生新解S':通过对当前解进行变换(如互换、置换等)产生新解。 计算增量ΔT=C(S')-C(S),其中C(S)为评价函数。 判断新解是否接受:若ΔT<0,则接受S'作为新的当前解;否则以概率exp(-ΔT/T)接受S'作为新的当前解。 如果满足终止条件(如连续若干个新解都没有被接受),则输出当前解

    2023年广西中小学生程序设计挑战赛初赛(入门组)试题及答案.pdf

    2023年广西中小学生程序设计挑战赛初赛(入门组)试题及答案.pdf

    基于深度学习的近红外光谱数据回归分析模型.zip

    基于深度学习的近红外光谱数据回归分析模型.zip

Global site tag (gtag.js) - Google Analytics