此篇作为ClickHouse的SQL优化的衍生篇,主要对MySQL/TiDB等映射表的使用角度进行初步探索。
基于下述的整体逻辑有点绕,特别是第三种意外发现的场景,简直就是不可以常理推导,存在一个非常大的不确定性。于是可对映射表在CH的SQL使用的做以下的最简洁的规范
SELECT A.a1, B.b1,toDate(A.a4) as dat
FROM A
[GLOBAL] [LEFT/INNER/RIGHT] JOIN B on A.a2 = B.b2
WHERE A.a3 = 'xxxx' and B.b3 = 'yyyy' and dat = '2021-11-21'
A表为驱动表,B表为被驱动表,ClickHouse对于驱动表与非驱动表的下推逻辑不同,总结下来有以下几点
SELECT A.a1, toDate(A.a4) as dat
FROM A
WHERE A.a3 = 'xxxx' and A.a5 >= '2021-11-21 00:00:00' and A.a5 <= '2021-11-21 23:59:59' [and dat = '2021-11-21']
在以上的单独子查询中,ClickHouse对映射表A的下推逻辑,总结下来有以下几点
SELECT A.
FROM (
SELECT a1, a2, a3, toDate(A.a4) as dat
FROM A
WHERE a3 = 'xxxx' and a5 >= '2021-11-21 00:00:00' and a5 <= '2021-11-21 23:59:59'
[and dat = '2021-11-21'] -- flag1
) A
LEFT JOIN B on A.a2 = B.b2
WHERE B.b3 = 'yyyy'
[and A.a3 = 'xxxx'] -- flag2
上述的代码案例中的逻辑最妖,具体表现如下
以下为大致的探索过程,由于使用的是CH,TiDB的慢查询记录,估为了构造慢查询,造成SQL不是很一致,以及大家在复现过程中可能需要多试几次
测试语句
select
if(vendor_create_time is null, toDate(create_time),toDate(vendor_create_time)) as dat
, ac.vendor_id as vendor_id
, ac.vendor_account_id as vendor_account_id
, eva.vendor_account_name as vendor_account_name
, eva.vendor_advertiser_id as vendor_advertiser_id
, eva.subordinate_account_id as subordinate_account_id
, ac.project_id as project_id
, count(distinct ac.id) as 1_in_creative
from makepolo.ad_creative ac
left join makepolo.entity_vendor_account eva on toInt64(eva.id)= toInt64(ac.vendor_account_id)
where ac.create_time >= '2021-11-01 00:00:00'
and ac.create_time <= '2021-11-22 23:59:59'
and dat >= '2021-11-01' and dat <= '2021-11-22'
and eva.status=1
and ac.company_id=20
group by
dat
,vendor_id
,vendor_account_id
,vendor_account_name
,vendor_advertiser_id
,subordinate_account_id
,project_id
['makepolo.ad_creative.company_id','makepolo.ad_creative.create_time','makepolo.ad_creative.id','makepolo.ad_creative.project_id','makepolo.ad_creative.vendor_account_id','makepolo.ad_creative.vendor_create_time','makepolo.ad_creative.vendor_id','makepolo.entity_vendor_account.id','makepolo.entity_vendor_account.status','makepolo.entity_vendor_account.subordinate_account_id','makepolo.entity_vendor_account.vendor_account_name','makepolo.entity_vendor_account.vendor_advertiser_id']
SELECT `id`, `vendor_id`, `vendor_account_id`, `company_id`, `project_id`, `create_time`, `vendor_create_time` FROM `makepolo`.`ad_creative` WHERE (`create_time` >= '2021-11-01 00:00:00') AND (`create_time` <= '2021-11-22 23:59:59') AND (`company_id` = 20);
测试语句
select
toDate(cr.date) as dat
, vaq.company_id as vaq_company_id
, vaq.subordinate_user_id as vaq_subordinate_user_id
, qcp.marketing_goal as qcp_marketing_goal
, sum(cr.stat_cost)/10000 as cost_n
, sum(if(qctv.create_source = 1, cr.stat_cost ,0))/10000 as api_cost
, sum(if(qcp.marketing_goal = 'VIDEO_PROM_GOODS', cr.stat_cost, 0))/10000 as video_cost
, sum(if(qctv.create_source = 1 and qcp.marketing_goal = 'VIDEO_PROM_GOODS', cr.stat_cost, 0))/10000 as video_api_cost
, sum(if(qcp.marketing_goal = 'LIVE_PROM_GOODS', cr.stat_cost, 0))/10000 as live_cost
, sum(if(qctv.create_source = 1 and qcp.marketing_goal = 'LIVE_PROM_GOODS', cr.stat_cost, 0))/10000 as live_api_cost
, 0 as creative_count
, 0 as api_creative_count
, 0 as ad_count
, 0 as api_ad_count
from makebenz.vendor_creative_report cr final
global join tidb_makebenz.vendor_account_qianchuan vaq on cr.advertiser_id = vaq.advertiser_id
left join tidb_makebenz.qc_vendor_creative qctv on cr.creative_id = qctv.creative_id
left join tidb_makebenz.qc_campaign qcp on cr.campaign_id = qcp.campaign_id
where
cr.date >= today() - 3 and cr.date <= today()
and cr.date >= '2021-11-12' and cr.date <= '2021-11-22'
and qctv.create_time >= '2021-11-01 00:00:00' and qctv.create_time <= '2021-11-22 23:59:59'
group by dat, vaq_company_id, vaq_subordinate_user_id, qcp_marketing_goal
tidb_makebenz.qc_vendor_creative
,tidb_makebenz.qc_campaign
的字段都完成了下推tidb_makebenz.vendor_account_qianchuan
的所有字段都被提取出来,并且有个临时表,这与GLOBAL的逻辑有关,这里不细述['_temporary_and_external_tables.`_tmp_0333ae46-cd1d-4285-8333-ae46cd1d0285`','_temporary_and_external_tables.`_tmp_70cc555b-adf2-465d-b0cc-555badf2c65d`','_temporary_and_external_tables.`_tmp_a59a3198-3857-4042-a59a-31983857c042`','_temporary_and_external_tables.`_tmp_b704469b-50d1-409d-b704-469b50d1409d`','_temporary_and_external_tables.`_tmp_bcdf62a5-84ef-41e0-bcdf-62a584efb1e0`','_temporary_and_external_tables.`_tmp_e3041940-3899-4f2c-a304-19403899ff2c`','makebenz.vendor_creative_report','makebenz.vendor_creative_report_local','tidb_makebenz.qc_campaign','tidb_makebenz.qc_vendor_creative','tidb_makebenz.vendor_account_qianchuan'] ['_temporary_and_external_tables.`_tmp_0333ae46-cd1d-4285-8333-ae46cd1d0285`.advertiser_id','_temporary_and_external_tables.`_tmp_0333ae46-cd1d-4285-8333-ae46cd1d0285`.company_id','_temporary_and_external_tables.`_tmp_0333ae46-cd1d-4285-8333-ae46cd1d0285`.subordinate_user_id','_temporary_and_external_tables.`_tmp_70cc555b-adf2-465d-b0cc-555badf2c65d`.advertiser_id','_temporary_and_external_tables.`_tmp_70cc555b-adf2-465d-b0cc-555badf2c65d`.company_id','_temporary_and_external_tables.`_tmp_70cc555b-adf2-465d-b0cc-555badf2c65d`.subordinate_user_id','_temporary_and_external_tables.`_tmp_a59a3198-3857-4042-a59a-31983857c042`.advertiser_id','_temporary_and_external_tables.`_tmp_a59a3198-3857-4042-a59a-31983857c042`.company_id','_temporary_and_external_tables.`_tmp_a59a3198-3857-4042-a59a-31983857c042`.subordinate_user_id','_temporary_and_external_tables.`_tmp_b704469b-50d1-409d-b704-469b50d1409d`.advertiser_id','_temporary_and_external_tables.`_tmp_b704469b-50d1-409d-b704-469b50d1409d`.company_id','_temporary_and_external_tables.`_tmp_b704469b-50d1-409d-b704-469b50d1409d`.subordinate_user_id','_temporary_and_external_tables.`_tmp_bcdf62a5-84ef-41e0-bcdf-62a584efb1e0`.advertiser_id','_temporary_and_external_tables.`_tmp_bcdf62a5-84ef-41e0-bcdf-62a584efb1e0`.company_id','_temporary_and_external_tables.`_tmp_bcdf62a5-84ef-41e0-bcdf-62a584efb1e0`.subordinate_user_id','_temporary_and_external_tables.`_tmp_e3041940-3899-4f2c-a304-19403899ff2c`.advertiser_id','_temporary_and_external_tables.`_tmp_e3041940-3899-4f2c-a304-19403899ff2c`.company_id','_temporary_and_external_tables.`_tmp_e3041940-3899-4f2c-a304-19403899ff2c`.subordinate_user_id','makebenz.vendor_creative_report.advertiser_id','makebenz.vendor_creative_report.campaign_id','makebenz.vendor_creative_report.creative_id','makebenz.vendor_creative_report.date','makebenz.vendor_creative_report.stat_cost','makebenz.vendor_creative_report_local.advertiser_id','makebenz.vendor_creative_report_local.campaign_id','makebenz.vendor_creative_report_local.creative_id','makebenz.vendor_creative_report_local.date','makebenz.vendor_creative_report_local.stat_cost','tidb_makebenz.qc_campaign.campaign_id','tidb_makebenz.qc_campaign.marketing_goal','tidb_makebenz.qc_vendor_creative.create_source','tidb_makebenz.qc_vendor_creative.create_time','tidb_makebenz.qc_vendor_creative.creative_id','tidb_makebenz.vendor_account_qianchuan.access_token','tidb_makebenz.vendor_account_qianchuan.access_token_expire','tidb_makebenz.vendor_account_qianchuan.account_type','tidb_makebenz.vendor_account_qianchuan.admin_advertiser_id','tidb_makebenz.vendor_account_qianchuan.admin_advertiser_name','tidb_makebenz.vendor_account_qianchuan.advertiser_id','tidb_makebenz.vendor_account_qianchuan.app_id','tidb_makebenz.vendor_account_qianchuan.authorizer_data','tidb_makebenz.vendor_account_qianchuan.company_id','tidb_makebenz.vendor_account_qianchuan.create_time','tidb_makebenz.vendor_account_qianchuan.id','tidb_makebenz.vendor_account_qianchuan.name','tidb_makebenz.vendor_account_qianchuan.name_as','tidb_makebenz.vendor_account_qianchuan.refresh_token','tidb_makebenz.vendor_account_qianchuan.refresh_token_expire','tidb_makebenz.vendor_account_qianchuan.remark','tidb_makebenz.vendor_account_qianchuan.status','tidb_makebenz.vendor_account_qianchuan.subordinate_user_id','tidb_makebenz.vendor_account_qianchuan.update_time','tidb_makebenz.vendor_account_qianchuan.user_id']
SELECT `creative_id`, `create_source`, `create_time` FROM `makebenz`.`qc_vendor_creative`
select id, company_id, vendor_id, vendor_account_id, project_id
, if(vendor_create_time is null, toDate(create_time), toDate(vendor_create_time)) as dat
from makepolo.ad_creative a
where a.create_time >= '2021-11-01 00:00:00'
and a.create_time <= '2021-11-01 23:59:59'
and dat >= '2021-11-01' and dat <= '2021-11-01'
and company_id=20
SELECT `id`, `vendor_id`, `vendor_account_id`, `company_id`, `project_id`, `create_time`, `vendor_create_time` FROM `makepolo`.`ad_creative` WHERE (`create_time` >= '2021-11-01 00:00:00') AND (`create_time` <= '2021-11-01 23:59:59') AND (`company_id` = 20);
-- 运行40S
select dat
, ac.vendor_id as vendor_id
, ac.vendor_account_id as vendor_account_id
, eva.vendor_account_name as vendor_account_name
, eva.vendor_advertiser_id as vendor_advertiser_id
, eva.subordinate_account_id as subordinate_account_id
, ac.project_id as project_id
, count(distinct ac.id) as 1_in_creative
from(
select id, company_id, vendor_id, vendor_account_id, project_id
, if(vendor_create_time is null, toDate(create_time), toDate(vendor_create_time)) as dat
from makepolo.ad_creative a
where a.create_time >= '2021-11-01 00:00:00'
and a.create_time <= '2021-11-01 23:59:59'
and dat >= '2021-11-01' and dat <= '2021-11-01'
and company_id=20
)ac
left join makepolo.entity_vendor_account eva on toInt64(eva.id)= toInt64(ac.vendor_account_id)
where eva.status = 1 and ac.company_id = 20
group by dat
, vendor_id
, vendor_account_id
, vendor_account_name
, vendor_advertiser_id
, subordinate_account_id
, project_id;
SELECT `id`, `vendor_id`, `vendor_account_id`, `company_id`, `project_id`, `create_time`, `vendor_create_time` FROM `makepolo`.`ad_creative` WHERE `company_id` = 20;
-- 运行3S
select dat
, ac.vendor_id as vendor_id
, ac.vendor_account_id as vendor_account_id
, eva.vendor_account_name as vendor_account_name
, eva.vendor_advertiser_id as vendor_advertiser_id
, eva.subordinate_account_id as subordinate_account_id
, ac.project_id as project_id
, count(distinct ac.id) as 1_in_creative
from(
select id, company_id, vendor_id, vendor_account_id, project_id
, if(vendor_create_time is null, toDate(create_time), toDate(vendor_create_time)) as dat
from makepolo.ad_creative a
where a.create_time >= '2021-11-01 00:00:00'
and a.create_time <= '2021-11-01 23:59:59'
and dat >= '2021-11-01' and dat <= '2021-11-01'
and company_id=20
)ac
left join makepolo.entity_vendor_account eva on toInt64(eva.id)= toInt64(ac.vendor_account_id)
where eva.status = 1 -- and ac.company_id = 20
group by dat
, vendor_id
, vendor_account_id
, vendor_account_name
, vendor_advertiser_id
, subordinate_account_id
, project_id;
and ac.company_id = 20
给注释掉,但从TiDB的INFORMATION_SCHEMA.slow_query的Query字段中可以看出
SELECT `id`, `vendor_id`, `vendor_account_id`, `company_id`, `project_id`, `create_time`, `vendor_create_time` FROM `makepolo`.`ad_creative` WHERE (`create_time` >= '2021-11-01 00:00:00') AND (`create_time` <= '2021-11-01 23:59:59') AND (`company_id` = 20);
-- 运行3S
select dat
, ac.vendor_id as vendor_id
, ac.vendor_account_id as vendor_account_id
, eva.vendor_account_name as vendor_account_name
, eva.vendor_advertiser_id as vendor_advertiser_id
, eva.subordinate_account_id as subordinate_account_id
, ac.project_id as project_id
, count(distinct ac.id) as 1_in_creative
from(
select id, company_id, vendor_id, vendor_account_id, project_id
, if(vendor_create_time is null, toDate(create_time), toDate(vendor_create_time)) as dat
from makepolo.ad_creative a
where a.create_time >= '2021-11-01 00:00:00'
and a.create_time <= '2021-11-01 23:59:59'
and company_id=20
)ac
left join makepolo.entity_vendor_account eva on toInt64(eva.id)= toInt64(ac.vendor_account_id)
where eva.status = 1 and ac.company_id = 20 and dat >= '2021-11-01' and dat <= '2021-11-01'
group by dat
, vendor_id
, vendor_account_id
, vendor_account_name
, vendor_advertiser_id
, subordinate_account_id
, project_id;
SELECT `id`, `vendor_id`, `vendor_account_id`, `company_id`, `project_id`, `create_time`, `vendor_create_time` FROM `makepolo`.`ad_creative` WHERE (`create_time` >= '2021-11-01 00:00:00') AND (`create_time` <= '2021-11-01 23:59:59') AND (`company_id` = 20);