SYBASE SQL 优化

线上项目,客户反映SQL执行特别慢,分析SQL得到,是某个子查询过慢,要优化,但想了很久不知道要怎么优化

数据库是SYBASE

问题相关代码,请勿粘贴截图

除去无关业务,SQL大致可以简化成这样
SELECT A.NAME,
A.AGE,
(SELECT COUNT(1) FROM B WHERE B.ID = A.ID AND B.NAME = '张三') NUM
FROM A
WHERE A.SEX = '1'
AND A.STATE IN ('1', '2')
ORDER BY A.CREATEDATE, A.LASTUPDATE

运行结果及报错内容

执行大概需要10几秒

我的解答思路和尝试过的方法

A表特别大,外部查A表的查询可能会返回几十万到几百万的数据,但是全走索引,仅查询A表并不慢,查询计划分析能知道,是从A表查询之后,执行子查询(SELECT COUNT(1) FROM B WHERE B.ID = A.ID AND B.NAME = '张三') 特别慢,因为A表返回几百万的数据,这里就要扫描几百万次B表,但是B表特别小,除去关联查询之后,(SELECT * FROM B WHERE B.NAME = '张三') 可能只会返回几十到几百条数据,现在想的是应该用B表驱动A表才对,但是外部A表的查询条件可能会特别多,查询的所有列除了这个COUNT之外都是A表的数据,可以说除了这个COUNT,这个查询和B表是没有关系的

我想要达到的结果

希望能把SQL优化到2s以下

既然是只取b表的部分数据,而且where中和B表无关,那这个为什么不直插a表分页后,内存上处理b表的条件,然后获取B表数据就可以了啊

在B表建立一个联合索引,将id和name作为索引中的两个字段试试,同时要保证联合索引的顺序,id在前,name在后,同时A表的CREATEDATE, LASTUPDATE最好也有索引


SELECT A.NAME,A.AGE,SUM(IF(B.NAME = '张三',1,0)) NUM 
FROM A 
LEFT JOIN B ON B.ID = A.ID
GROUP BY A.ID 
HAVING A.SEX = '1' AND A.STATE IN ('1', '2')
ORDER BY A.CREATEDATE, A.LASTUPDATE

SELECT A.NAME,
A.AGE,A.ID
FROM A
left join 
(select B.ID,count(1) num from B where B.NAME='张三' GROUP BY B.ID) C
on C.ID=A.ID
WHERE A.SEX = '1'
AND A.STATE >= 1 and A.STATE <=  2
ORDER BY A.CREATEDATE, A.LASTUPDATE

把排序去掉应该更快点

把子查询改为内关联,关联字段上建索引。B的NAME字段上加上NAME字段索引。
select A.NAME,
A.AGE,COUNT(*) NUM
from A JOIN B ON A.ID=B.ID
where A.SEX = '1'
AND A.STATE IN ('1', '2')
AND B.NAME = '张三'
group by A.NAME,
A.AGE
然后看看这样查慢不慢

SELECT A.NAME,
A.AGE,
COUNT(b.name)  NUM
FROM A
Join B on a.id=b.id and a.name=b.name
WHERE A.SEX = '1'
AND A.STATE IN ('1', '2')
group by A.NAME,A.AGE
ORDER BY A.CREATEDATE, A.LASTUPDATE

同时为id,name,sex,state创建索引

撇开索引这些先不谈 【SELECT COUNT(1) FROM B WHERE B.ID = A.ID AND B.NAME = '张三' 】这句查询作为字段本身就很影响性能