Mysql 優化方案

Mysql 優化方案

運行狀態查詢

瞭解mysql數據庫的一些運行狀態如何查詢(比如想知道當前mysql運行的時間/一共執行了多少次select/update/delete.. / 當前連接)

show [seesion| gloable] status like ….
如:
//查詢運行時間
show status like ‘uptime’;
//select | insert |delete 語句執行次數
show status like ‘com_select’
show status like ‘com_insert’
show status like ‘com_delete’
// 查詢鏈接次數
show status like ‘connections’
// 查詢慢查詢語句
show status like 'slow_queries';
//默認慢查詢時間10秒
show variables like ‘long_query_time’;
set long_query_time=1 ;//可以修改慢查詢時間
// 慢查詢設置my.ini
log-slow-queries = D:/Mysql/mysql-5.6.27-winx64/slowquery.log
long_query_time = 2

字段優化

儘量使用TINYINT、SMALLINT、MEDIUM_INT作爲整數類型而非INT,如果非負則加上UNSIGNED
VARCHAR的長度只分配真正需要的空間
儘量使用TIMESTAMP而非DATETIME,
單表不要有太多字段,建議在20以內
避免使用NULL字段,很難查詢優化且佔用額外索引空間 default ”
用整型來存IP

索引使用優化

  1. 查詢是否使用索引 關鍵字:explain select …
  2. like 避免使用 %key(前匹配)
  3. 避免使or,適當用in 代替
  4. 字段類型爲字符串 必須用” 引起來,否則索引失效
  5. group by colm 默認會排序,建議使用 後面加order by null
  6. 能用鏈接的不用子查詢
  7. 避免在where 子句中使用is null 判斷 可以使用is not null
  8. 值很少的字段不適合建立索引
  9. 字符字段最好不要做主鍵
  10. 使用多列索引時主意順序和查詢條件保持一致,同時刪除不必要的單列索引
  11. 強制使用某索引 select * from table force index(indexname)或use
  12. 前綴索引,當字段長度超過255需要定義截取 255
  13. 索引是表達式或函數的參數,索引被破壞
  14. 避免where 子句使用 != 和<> ,索引被破壞
  15. 對於連續數字,使用between a and b 代替 in

補充:索引使用定位

id

        查詢順序標識
            如:mysql> explain select * from (select nid,name from tb1 where nid < 10) as B;
            +----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
            | id | select_type | table      | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
            +----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
            |  1 | PRIMARY     | <derived2> | ALL   | NULL          | NULL    | NULL    | NULL |    9 | NULL        |
            |  2 | DERIVED     | tb1        | range | PRIMARY       | PRIMARY | 8       | NULL |    9 | Using where |
            +----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
        特別的:如果使用union連接氣值可能爲null

select_type

        查詢類型
            SIMPLE          簡單查詢
            PRIMARY         最外層查詢
            SUBQUERY        映射爲子查詢
            DERIVED         子查詢
            UNION           聯合
            UNION RESULT    使用聯合的結果
            ...
table

        正在訪問的表名

type

    查詢時的訪問方式,性能:all < index < range < index_merge < ref_or_null < ref < eq_ref < system/const
    ALL   全表掃描,對於數據表從頭到尾找一遍
            select * from tb1;
            特別的:如果有limit限制,則找到之後就不在繼續向下掃描
                select * from tb1 where email = '[email protected]'
                select * from tb1 where email = '[email protected]' limit 1;
                雖然上述兩個語句都會進行全表掃描,第二句使用了limit,則找到一個後就不再繼續掃描。

    INDEX  全索引掃描,對索引從頭到尾找一遍
           select nid from tb1;

    RANGE  對索引列進行範圍查找
           select *  from tb1 where name < 'alex';
           PS:
             between and
             in
             >   >=  <   <=  操作
             注意:!= 和 > 符號

    INDEX_MERGE 合併索引,使用多個單列索引搜索
                select *  from tb1 where name = 'alex' or nid in (11,22,33);

    REF   根據索引查找一個或多個值
          select *  from tb1 where name = 'seven';

    EQ_REF  連接時使用primary key 或 unique類型
            select tb2.nid,tb1.name from tb2 left join tb1 on tb2.nid = tb1.nid;

    CONST  常量
           表最多有一個匹配行,因爲僅有一行,在這行的列值可被優化器剩餘部分認爲是常數,const表很快,因爲它們只讀取一次。
           select nid from tb1 where nid = 2 ;

    SYSTEM 系統
           表僅有一行(=系統表)。這是const聯接類型的一個特例。
           select * from (select nid from tb1 where nid = 1) as A;

possible_keys

        可能使用的索引

key

        真實使用的

key_len

        MySQL中使用索引字節長度

rows

        mysql估計爲了找到所需的行而要讀取的行數 ------ 只是預估值

extra

        該列包含MySQL解決查詢的詳細信息
        “Using index”
            此值表示mysql將使用覆蓋索引,以避免訪問表。不要把覆蓋索引和index訪問類型弄混了。
        “Using where”
            這意味着mysql服務器將在存儲引擎檢索行後再進行過濾,許多where條件裏涉及索引中的列,當(並且如果)它讀取索引時,就能被存儲引擎檢驗,因此不是所有帶where子句的查詢都會顯示“Using where”。有時“Using where”的出現就是一個暗示:查詢可受益於不同的索引。
        “Using temporary”
            這意味着mysql在對查詢結果排序時會使用一個臨時表。
        “Using filesort”
            這意味着mysql會對結果使用一個外部索引排序,而不是按索引次序從表裏讀取行。mysql有兩種文件排序算法,這兩種排序方式都可以在內存或者磁盤上完成,explain不會告訴你mysql將使用哪一種文件排序,也不會告訴你排序會在內存裏還是磁盤上完成。
        “Range checked for each record(index map: N)”

分表優化

` 數據大 且訪問量大 建議使用分表(也可以聯合搭配分區)

除非單表數據未來會一直不斷上漲,否則不考慮拆分,拆分會帶來 邏輯部署等複雜問題,分表和表分區的目的就是減少數據庫的負擔,提高數據庫的效率,通常點來講就是提高表的增刪改查效率。

分表的特點:
1. 將一個大表按一定規則分解成多張具有 獨立的存儲空間實體子表
2. 獨立的數據文件、索引文件、表結構文件
3. 可以分佈到不同機器、磁盤上
4. 按照規則訪問定義好的子表

使用: 分表需要創建表,使用和維護比較麻煩

分區

訪問量不大,但是數據量大建議使用分區
1. 分區的好處是:
表面看還是一張表,是將數據分段存儲到多個位置
訪問還是一張表
分區表的數據更容易維護,可以通過清楚整個分區批量刪除大量數據,也可以增加新的分區來支持新插入的數據。另外,還可以對一個獨立分區進行優化、檢查、修復等操作
部分查詢能夠從查詢條件確定只落在少數分區上,速度會很快
分區表的數據還可以分佈在不同的物理設備上
可以使用分區表賴避免某些特殊瓶頸,例如InnoDB單個索引的互斥訪問、ext3文件系統的inode鎖競爭
可以備份和恢復單個分區

四種分區 使用方法:
查詢是否支持分區:SHOW VARIABLES LIKE ‘%partition%’;
1. Range 分區

-- 創建分區
DROP TABLE IF EXISTS t_range_text;
CREATE TABLE t_range_text(
   id INT(64) NOT NULL auto_increment ,
   `name` VARCHAR(64) NOT NULL DEFAULT '',
   -- 這裏需要設置爲datatime 不能設置timesimple
   createTime datetime NOT NULL,
   -- 分區的字段需要建立索引
   primary KEY(id,`createTime`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8  
PARTITION BY RANGE (year(createTime))
(
    PARTITION 2000_year VALUES less than(2000),
    PARTITION 2005_year VALUES less than(2005),
    PARTITION 2010_year VALUES less than(2010),
    PARTITION 2015_year VALUES less than(2015),
    PARTITION other_year VALUES less than MAXVALUE
);
-- 查看PARTITIONS字段是否使用分區
EXPLAIN PARTITIONS  SELECT * FROM t_range_text;

-- 刪除數據或者刪除分區
ALTER TABLE t_range_text DROP PARTITION 2000_year; 

-- 增加分區(有maxvalue分區無法加,且只範圍參數只能變大不能變小)
ALTER TABLE t_range_text ADD PARTITION (PARTITION 2000_year VALUES LESS THAN (2000)); 

-- 合併分區
ALTER TABLE t_range_text
REORGANIZE PARTITION 2005_year,2010_year,2015_year  INTO
(
PARTITION 2015_year VALUES LESS THAN (2015)
)

2 . LIST 分區

CREATE TABLE t_list_text(  
    id INT NOT NULL,  
    fname VARCHAR(30),   
    store_id INT  
)   
PARTITION BY LIST(store_id)  
    PARTITION one VALUES IN (3,5,6,9,17),  
    PARTITION two VALUES IN (1,2,10,11,19,20),  
    PARTITION three VALUES IN (4,12,13,14,18),  
    PARTITION fore VALUES IN (7,8,15,16)  
);

-- 插入數據需注意 store_id 必須在列表中
insert into t_list_text values(1,'11',33);X

3 HASH分區

CREATE TABLE employees (  
    id INT NOT NULL,  
    fname VARCHAR(30),   
    store_id INT  
)  
PARTITION BY HASH(store_id)  
PARTITIONS 4;

-- PARTITION BY LINER HASH(store_id) 線性hash是2的冪運算(普通的是取模運算)
-- 優點:在於增加、刪除、合併和拆分分區將變得更加快捷
-- 缺點:常規HASH分區得到的數據分佈相比,各個分區間數據的分佈不大可能均衡。

5 key 分區

create table t_key( 
  a int(11), 
  b datetime
) 
partition by key (b) 
partitions 4;

-- PARTITION BY LINER key(store_id) 線性hash是2的冪運算(普通的是取)
-- 優點:在於增加、刪除、合併和拆分分區將變得更加快捷
-- 缺點:常規HASH分區得到的數據分佈相比,各個分區間數據的分佈不大可能均衡。

讀寫分離

主-從讀寫分離在該文章中實現:
http://blog.csdn.net/u012442381/article/details/77141781

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章