優化案例 分割槽表場景下的SQL優化

2021-09-23 16:06:44 字數 3599 閱讀 8084

有個表做了分割槽,每天乙個分割槽。

該錶上有個查詢,經常只查詢表中某一天資料,但每次都幾乎要掃瞄整個分割槽的所有資料,有什麼辦法進行優化嗎?

有乙個大表,每天產生的資料量約100萬,所以就採用表分割槽方案,每天乙個分割槽。

下面是該錶的ddl:

create table `t1` (

`id` bigint(20) not null auto_increment,

`date` date not null,

`kid` int(11) default '0',

`uid` int(11) not null,

`iid` int(11) default '0',

`icnt` int(8) default '0',

`tst` timestamp not null default current_timestamp on update current_timestamp,

`countp` smallint(11) default '1',

`isr` int(2) not null default '0',

`clv` int(5) not null default '1',

primary key (`id`,`date`),

unique key `date` (`date`,`uid`,`iid`),

key `date_2` (`date`,`kid`)

) engine=innodb auto_increment=3180686682 default charset=utf8mb4

/*!50500 partition by range columns(`date`)

(partition p20161201 values less than ('2016-12-02') engine = innodb,

partition p20161202 values less than ('2016-12-03') engine = innodb,

partition p20161203 values less than ('2016-12-04') engine = innodb,

...

該錶上經常發生下面的慢查詢:

select ... from `t1` where `date` = '2017-04-01' and `icnt` > 300 and `id` = >'iid';

想要優化乙個sql,一般來說就是先看執行計畫,觀察是否盡可能用到索引,同時要關注預計掃瞄的行數,以及是否產生了臨時表(using temporary) 或者 是否需要進行排序(using filesort),想辦法消除這些情況。

更進一步的優化策略則可能需要調整程式**邏輯,甚至技術架構或者業務需求,這個動作比較大,一般非核心系統上的核心問題,不會這麼大動干戈,絕大多數情況,還是需要靠dba盡可能發揮聰明才智來解決。

現在,我們來看下這個sql的執行計畫:

[email protected][mydb]> explain partitions select ... from `t1` where 

`date` = '2017-03-02' and `icnt` > 100 and `iid` = '502302'\g

*************************** 1. row ***************************

id: 1

select_type: ******

table: t1

partitions: p20170302

type: range

possible_keys: date,date_2

key: date

key_len: 3

ref: const

rows: 9384602

extra: using where

這個執行計畫看起來還好,有索引可用,也沒臨時表,也沒filesort。不過,我們也注意到,預計要掃瞄的行數還是挺多的 rows: 9384602,而且要掃瞄zheng整個分割槽的所有資料,難怪效率不高,總是slow query。

我們注意到這個sql總是要查詢某一天的資料,這個表已經做了按天分割槽,那是不是可以忽略 where 子句中的 時間條件呢?

還有,既然去掉了 date 條件,反觀表ddl,剩下的條件貌似就沒有合適的索引了吧?

所以,我們嘗試新建乙個索引:

[email protected][mydb]> alter table t1 add index iid (iid, icnt);

然後,把sql改造成下面這樣,再看下執行計畫:

[email protected][mydb]> explain partitions select ... from `t1` partition(p2017030) where 

`icnt` > 100 and `iid` = '502302'\g

*************************** 1. row ***************************

id: 1

select_type: ******

table: t1

partitions: p20170302

type: ref

possible_keys: date,date_2,iid

key: iid

key_len: 10

ref: const

rows: 7800

extra: using where

這優化效果,槓槓滴。

事實上,如果不強制指定分割槽的話,也是可以達到優化效果的:

[email protected][mydb]> explain partitions select ... from `t1` where 

`date` = '2017-03-02' and `icnt` > 100 and `iid` = '502302'\g

*************************** 1. row ***************************

id: 1

select_type: ******

table: t1

partitions: p20170302

type: ref

possible_keys: date,date_2,iid

key: iid

key_len: 10

ref: null

rows: 7800

extra: using where

絕大多數的sql通過新增索引、適當調整sql**(例如調整驅動表順序)等簡單手法來完成。

多說幾句,遇到sql優化效能瓶頸問題想要在技術群裡請教時,麻煩先提供幾個必要的資訊:

SQL SERVER2005分割槽表建立SQL

建立分割槽表之前,請在新建資料前新增資料庫檔案和檔案組 檔案組數 分割槽數 建立分割槽函式 有三個範圍會產生四個分割槽 create partition function fiveyeardaterangepfn datetime asrange left for values 20061031 2...

建分割槽表索引優化SQL

sql 優化的 分類早就有了,就是碰不到 優化的典型例子,今天遇到乙個.頁面上面的sql select count from taba.npai,dm area da where npai.local area id 3 and npai.area id da.area id 第一次跑 65s 讓人...

hive 分割槽表 Hive的DDL分割槽表建立

1.單分割槽表 建立表t user,指定分割槽hive xiaoliu create table t user id int,name string partitioned by country string row format delimited fields terminated by xia...