關於阿里雲 RDS mysql索引優化的一點經驗

2019年9月5日10:02:34html

本地調試node

 git https://github.com/barryvdh/laravel-debugbar mysql

composer require barryvdh/laravel-debugbar --dev
APP_DEBUG TRUE

配置.envlaravel

本地調試很方便,千萬不要弄到線上去了,由於這個東西其實很消耗資源的git

 

  公司的項目,由於使用workerman作消息推送,我以前想是作主從,可是想到須要額外花費,並且目前大部分是內部使用,就開始了優化mysql之路github

  框架使用的是laravel5.7,基本都要求使用orm,可是框架裏面還有有小部分使用的複雜使用的原生的,不少使用聯表,注意這裏的聯表不是join聯表,由於性能差別sql

  

  查詢使用的工具都是阿里雲提供的工具數據庫

  阿里雲ApsaraDB診斷報告,SQL洞察分析,app

  ApsaraDB診斷報告對檢查慢查詢仍是頗有效的,很容易找到問題去優化composer

一個demo

SELECT * FROM `sale_out_storage` WHERE `shop_id` = ? AND `is_delete` = ? AND `storage_status` = ? AND NOT EXISTS ( SELECT * FROM `k3_sale_out_storage_task` WHERE `sale_out_storage`.`id` = `k3_sale_out_storage_task`.`sale_out_storage_id` AND `is_delete` = ? AND `is_cancel` = ? AND `status` IN (?) AND `shop_id` = ? ) AND EXISTS ( SELECT * FROM `sale_order` WHERE `sale_out_storage`.`sale_order_id` = `sale_order`.`id` AND `order_status` != ? ) AND `storage_date` > ? 建議 1. 返回記錄數 語句最大返回記錄數爲55。

2. 行掃描 行掃描與行返回之比爲178673。

3. 索引 該語句沒有使用聚合函數和模糊查詢,行掃描與行返回之比很高。建立合理索引會帶 來很大的優化空間

 

SQL語句
數據庫
線程ID
用戶
客戶端IP
操做
狀態
耗時(ms)
執行時間
更新行數
掃描行數
select `id`, `user_id`, `admin_id`, `type`, `type_flag`, `content`, `operation_user_id`, `operation_admin_id`, `is_read`, `shop_id`, `message_tag`, `message_type`, `create_time` from `operation_log` where `admin_id` = 14 and `operation_admin_id` != 14 and `is_read` = 1 and `message_type` in (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19) and `create_time` >= '2019-06-01 00:00:00' order by `id` desc limit 10 offset 0
v2
60130
youse
172.18.112.8
SELECT
成功
0.25
2019年9月6日 10:57:50
0
13
select count(*) as aggregate from `operation_log` where `user_id` = ? and `is_read` = ?
v2
24
youse
172.18.112.8
SELECT
成功
0.04
2019年9月6日 10:57:50
0
0
select * from `sale_voucher` where `is_delete` = 10 and `shop_id` = 1 and `admin_id` = 14 and `status` = 30 and `create_time` >= '2019-01-01' order by `id` desc limit 5 offset 0
v2
60130
youse
172.18.112.8
SELECT
成功
0.48
2019年9月6日 10:57:50
0
289
select `id`, `user_id`, `admin_id`, `type`, `type_flag`, `content`, `operation_user_id`, `operation_admin_id`, `is_read`, `shop_id`, `message_tag`, `message_type`, `create_time` from `operation_log` where `admin_id` = ? and `operation_admin_id` != ? and `is_read` = ? and `message_type` in (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) and `create_time` >= ? order by `id` desc limit 10 offset 0
v2
60130
youse
172.18.112.8
SELECT
成功
0.12
2019年9月6日 10:57:50
0
0
 
                   
select * from `admin_permission` where `is_delete` = 10 and `id` in (1, 3, 69, 148,, 439, 440, 428, 429, 430, 431, 432, 433, 444, 115, 244, 245, 246, 247, 248, 249, 239, 389, 390, 129, 331, 332, 333, 334, 391, 392, 393, 394, 395, 149)
v2
60130
youse
172.18.112.8
SELECT
成功
1.04
2019年9月6日 10:57:50
0
527

 

我發現的最大的問題有如下幾點:

  1,where in的性能其實不好,常常須要大範圍掃描,減小in的範圍,或者使用exists代替

  2,使用時間範圍查詢的時候必定要加上索引,否則效率不好,大範圍掃描行數

  3,索引不能添加過多,過多也會致使性能降低,好比log日誌表,提供給多方查詢的時候,添加過多,mysql內部多個索引進行查詢的時候,會增長計算量,大大消耗cpu

  4,若是有多個索引好比訂單表,請注意必定優先最左原則,最大化利用索引,強調代碼規範

  5,join 會大大增長內存消耗,即便在符合大表連小表的原則

  6,適當添加索引,特別是在laravel with聯表的時候

$parent_sale_order_info = SaleOrder::where('shop_id', $shop_id)->where('is_delete', 10)
                ->with([
                    'sale_order' => function ($query) {
                        $query->where('is_delete', 10)->with([
                            'sale_out_storage' => function ($query) {
                                $query->where('is_delete', 10)->where('storage_status', 20)->with([
                                    'sale_out_storage_sku' => function ($query) {
                                        $query->where('is_delete', 10);
                                    }
                                ]);
                            },
                            'sale_pay' => function ($query) {
                                $query->where('is_delete', 10);
                            }
                        ]);
                    },
                    'sale_settle' => function ($query) {
                        $query->where('is_delete', 10)->with([
                            'sale_settle_sku' => function ($query) {
                                $query->where('is_delete', 10);
                            }
                        ]);
                    },
                    'sale_pay_record' => function ($query) {
                        $query->where('is_delete', 10)->where('status', 20);
                    }
                ])
                ->where('id', $parent_order_id)
                ->first();

 

優化完的結果

 

有平常80%-95%,優化完以後30%上下,阿里雲的rds mysql 5.7,2核4g

補充一點,核心的解決辦法就是找到出問題點在哪,我這個場景就是由於推送大大增長數據查詢消耗,致使mysql掃描行大大增長

 

解決思路以下:瞭解業務的繁忙點,找到頻繁的核心表,優先嚐試,優化索引,這樣的就不須要修改不少代碼,若是發現只優化索引不能解決,堅定修改代碼,並指導開發人員是爲何須要這樣寫

更改書寫習慣和理念,這樣才能根本解決問題,否則只是臨時救火。

 

一點參考的文章

https://www.cnblogs.com/ManyQian/p/9076247.html#_label2

https://www.cnblogs.com/ManyQian/p/9038063.html

https://www.cnblogs.com/ManyQian/p/9026606.html

https://www.cnblogs.com/zjxiang/p/9160810.html

相關文章
相關標籤/搜索