达梦不支持filter类型的执行路径导致慢SQL

达梦不支持filter类型的执行路径导致慢SQL

最近有个政府项目的库往政务云上迁移到达梦库,源库的业务量不是很大,库本身也不大。

迁移后抓取达梦的AWR,发现有一条SQL每次执行需要15s多,而在原来的Oracle里边执行0.1s。

查看后发现是达梦不支持filter执行路径导致的。

模拟如下:

创建dgd,p,s共3个表。

create table dgd (hsstr varchar2(20),exstr varchar2(20));
create table p   (id number);
create table s   (id number,hs_str varchar2(40));

业务SQL如下:

select * from dgd
where exists (select 1
from p, s
where p.id = s.id
and dgd.hsstr || dgd.exstr like s.hs_str || '%');

SQL为半连接,关联条件使用了like,因此无论是在Oracle还是达梦都无法使用HASH JOIN算法。

SQL在Oracle和达梦的执行计划如下:

在Oracle和达梦里边,P和S表都使用了HASH JOIN算法。

由于Oracle的FILTER有去重效果,会减少ID为3,4,5的执行次数,

而在达梦里边,NEST LOOP SEMI JOIN2会导致ID为6,7,8的执行次数为DGD的结果集数,没有去重效果。

因此在驱动表关联字段重复数据多的情况下,因为无去重导致达梦实际上就慢很多了。

Oracle:
Plan hash value: 166352517

-----------------------------------------------------------------------------------------------------------------
| Id  | Operation           | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
-----------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |      |      1 |        |      0 |00:00:00.01 |       3 |       |       |          |
|*  1 |  FILTER             |      |      1 |        |      0 |00:00:00.01 |       3 |       |       |          |
|   2 |   TABLE ACCESS FULL | DGD  |      1 |      1 |      0 |00:00:00.01 |       3 |       |       |          |
|*  3 |   HASH JOIN         |      |      0 |      1 |      0 |00:00:00.01 |       0 |  1393K|  1393K|          |
|   4 |    TABLE ACCESS FULL| P    |      0 |      1 |      0 |00:00:00.01 |       0 |       |       |          |
|*  5 |    TABLE ACCESS FULL| S    |      0 |      1 |      0 |00:00:00.01 |       0 |       |       |          |
-----------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter( IS NOT NULL)
   3 - access("P"."ID"="S"."ID")
   5 - filter(:B1||:B2 LIKE "S"."HS_STR"||'%')


达梦:
1   #NSET2: [1, 1, 108] 
2     #PRJT2: [1, 1, 108]; exp_num(3), is_atom(FALSE) 
3       #NEST LOOP SEMI JOIN2: [1, 1, 108];  join condition(DGD.HSSTR || DGD.EXSTR LIKE S.HS_STR || '%')[with var]
4         #CSCN2: [1, 1, 108]; INDEX33557305(DGD)
5         #SLCT2: [1, 1, 108]; var4 LIKE S.HS_STR || '%'
6           #HASH2 INNER JOIN: [1, 1, 108];  KEY_NUM(1); KEY(P.ID=S.ID) KEY_NULL_EQU(0)
7             #CSCN2: [1, 1, 30]; INDEX33557306(P)
8             #CSCN2: [1, 1, 78]; INDEX33557308(S)

仔细看上边达梦的执行计划,[with var]表示使用了变量改写方式实现连接。

使用hint禁止变量改写之后,执行计划如下:

还是无法避免NEST LOOP。

1   #NSET2: [14, 1, 108] 
2     #PRJT2: [14, 1, 108]; exp_num(3), is_atom(FALSE) 
3       #NEST LOOP SEMI JOIN2: [14, 1, 108];  join condition(DGD.HSSTR || DGD.EXSTR LIKE S.HS_STR || '%')
4         #CSCN2: [1, 1, 108]; INDEX33557305(DGD)
5         #HASH2 INNER JOIN: [1, 1, 108];  KEY_NUM(1); KEY(P.ID=S.ID) KEY_NULL_EQU(0)
6           #CSCN2: [1, 1, 30]; INDEX33557306(P)
7           #CSCN2: [1, 1, 78]; INDEX33557308(S)

关于变量改写,资料太少。官网也搜不到详细的介绍信息。

只有相关hint的时候提到了一下:SQL调优连接方法hint

现在发现把半连接改写为内连接在达梦则可以加快速度。

如下:

select dgd.* from dgd,p,s
where p.id = s.id
and dgd.hsstr || dgd.exstr like s.hs_str || '%';

找个时间再研究研究。

拓展

当半连接的关联条件为等价连接则可以使用HASH JOIN算法了。

但是需要各自添加hint。

Oracle                                                                                                                      达梦:
select * from dgd                                                                                                           explain select /*+ NO_USE_CVT_VAR OPTIMIZER_MODE(1) */ * from dgd
where exists (select /*+ unnest hash_sj */ 1                                                                                where exists (select  1
from p, s                                                                                                                   from p, s
where p.id = s.id                                                                                                           where p.id = s.id
and dgd.hsstr = s.hs_str );                                                                                                 and dgd.hsstr = s.hs_str );
                                                                                                                            
                                                                                                                            1   #NSET2: [1, 1, 108] 
Plan hash value: 1223244540                                                                                                 2     #PRJT2: [1, 1, 108]; exp_num(3), is_atom(FALSE) 
                                                                                                                            3       #HASH LEFT SEMI JOIN2: [1, 1, 108]; KEY_NUM(1);  KEY(DGD.HSSTR=DMTEMPVIEW_889204724.colname) KEY_NULL_EQU(0)
---------------------------------------------------------------------------------------------------------------------       4         #CSCN2: [1, 1, 108]; INDEX33557305(DGD)
| Id  | Operation            | Name    | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |       5         #PRJT2: [1, 1, 108]; exp_num(1), is_atom(FALSE) 
---------------------------------------------------------------------------------------------------------------------       6           #HASH2 INNER JOIN: [1, 1, 108];  KEY_NUM(1); KEY(P.ID=S.ID) KEY_NULL_EQU(0)
|   0 | SELECT STATEMENT     |         |      1 |        |      0 |00:00:00.01 |       1 |       |       |          |       7             #CSCN2: [1, 1, 30]; INDEX33557306(P)
|*  1 |  HASH JOIN SEMI      |         |      1 |      1 |      0 |00:00:00.01 |       1 |  1160K|  1160K|  451K (0)|       8             #CSCN2: [1, 1, 78]; INDEX33557308(S)
|   2 |   TABLE ACCESS FULL  | DGD     |      1 |      1 |      0 |00:00:00.01 |       1 |       |       |          |       
|   3 |   VIEW               | VW_SQ_1 |      0 |      1 |      0 |00:00:00.01 |       0 |       |       |          |       used time: 1.409(ms). Execute id is 0.
|*  4 |    HASH JOIN         |         |      0 |      1 |      0 |00:00:00.01 |       0 |  1393K|  1393K|          |
|   5 |     TABLE ACCESS FULL| P       |      0 |      1 |      0 |00:00:00.01 |       0 |       |       |          |
|   6 |     TABLE ACCESS FULL| S       |      0 |      1 |      0 |00:00:00.01 |       0 |       |       |          |
---------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("DGD"."HSSTR"="ITEM_1")
   4 - access("P"."ID"="S"."ID")
<think>好的,我现在需要回答用户关于如何创建数据库的问题,特别是结合用户提供的引用内容。首先,用户提到的引用涉及MySQL 5.7、Django初始化、达梦数据库、Mariadb和PostgreSQL的初始化步骤。所以我的回答需要覆盖这些不同的数据库系统,同时保持结构清晰。 首先,我应该分步骤说明通用的数据库创建流程,可能包括安装、初始化、配置和验证。然后,针对不同数据库系统分别给出具体的方法,引用用户提供的资料作为例子。比如,MySQL 5.7的初始化方法不同,需要特别说明;Django的post_migrate信号可以用来初始化数据;达梦数据库的重初始化步骤;Mariadb和PostgreSQL的配置调整。 需要确保回答中的技术细节正确,比如MySQL 5.7使用mysqld --initialize命令,而之前的版本可能用mysql_install_db。还要注意用户提到的初始化数据库时可能遇到的问题,比如DATA目录不存在,需要强调正确的初始化步骤。 另外,用户可能对各个数据库的具体命令和配置文件位置不太清楚,要详细说明。比如PostgreSQL的配置文件路径是/var/lib/pgsql/data/下的postgresql.conf和pg_hba.conf,修改后需要重启服务。同时,要提到如何远程连接数据库,可能需要调整监听地址和认证方法。 最后,生成的相关问题要围绕用户可能的后续疑问,比如性能优化、初始化失败处理、安全性设置等,确保问题有针对性,帮助用户进一步学习。 需要检查每个步骤是否覆盖了用户提供的引用内容,并且正确标注引用标记。例如,在MySQL初始化部分引用[^1],Django部分引用[^2]等。确保LaTeX格式正确,虽然问题中可能不需要太多数学公式,但如果有变量或代码块,要正确使用格式。 可能还需要注意不同数据库系统的差异,比如达梦数据库使用SYSDBA账户和密码初始化,而PostgreSQL使用psql命令创建数据库。同时,提醒用户初始化会重置账户密码,如达梦数据库的例子[^3]。 最后,确保回答结构清晰,分点说明,代码块使用正确的语法高亮,比如Python代码示例在Django部分。并且相关问题部分要涵盖用户可能关心的其他方面,如性能、安全、迁移等。</think>### 创建数据库的通用步骤 创建数据库通常分为安装数据库软件、初始化配置、创建实例和权限管理四个阶段。以下是详细操作流程: --- #### **1. 安装数据库软件** - 根据数据库类型(如MySQL、PostgreSQL、MariaDB等)下载对应安装包并执行安装命令。 - 例如,在Ubuntu中安装MySQL: ```bash sudo apt-get install mysql-server ``` --- #### **2. 初始化数据库** **关键步骤:生成系统表结构和默认配置** - **MySQL 5.7+**: 使用`mysqld --initialize`命令生成默认的`DATA`目录和系统库。 ```bash mysqld --initialize --user=mysql --basedir=/usr/local/mysql --datadir=/data/mysql ``` - **达梦数据库**: 通过`dminit`工具重新初始化实例,重置密码为`SYSDBA/SYSDBA`[^3]。 - **PostgreSQL**: 使用`initdb`命令初始化数据目录: ```bash initdb -D /var/lib/pgsql/data ``` --- #### **3. 启动服务并配置远程访问** - 启动服务: ```bash systemctl start mysql # MySQL systemctl start postgresql # PostgreSQL ``` - **远程连接配置**: - **MariaDB/MySQL**:修改`my.cnf`中`bind-address = 0.0.0.0`并授权用户[^4]。 - **PostgreSQL**:修改`postgresql.conf`中的`listen_addresses = '*'`和`pg_hba.conf`的IP白名单[^5]。 --- #### **4. 创建用户和数据库** 通过SQL命令或工具创建: ```sql -- MySQL示例 CREATE DATABASE mydb; CREATE USER 'user'@'%' IDENTIFIED BY 'password'; GRANT ALL PRIVILEGES ON mydb.* TO 'user'@'%'; ``` --- #### **5. 框架集成(如Django)** 使用Django的`post_migrate`信号初始化数据(例如创建管理员账号): ```python # signals.py from django.db.models.signals import post_migrate from django.contrib.auth.models import User def create_admin(sender, **kwargs): if not User.objects.filter(username='admin').exists(): User.objects.create_superuser('admin', 'admin@example.com', 'admin123') post_migrate.connect(create_admin) ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值