亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

搜索
博主信息
博文 54
粉絲 6
評論 31
訪問量 124128
最新下載
更多>
網(wǎng)站特效
網(wǎng)站源碼
網(wǎng)站素材
前端模板
Laravel8的數(shù)據(jù)庫操作和優(yōu)化建議
吾逍遙
原創(chuàng)
5097人瀏覽過

一、前言

PHP的PDO對數(shù)據(jù)庫,尤其是MySQL提供了全面的CURD、預處理和事務的支持,框架無論是Laravel或ThinkPHP都是基于它封裝成類,便于用戶操作數(shù)據(jù)庫。關于PHP的數(shù)據(jù)庫操作我以前歸納為兩個重點:SQL語句和PDO操作,不清楚可以看下我的博文《SQL操作數(shù)據(jù)庫和PDO操作數(shù)據(jù)庫》http://ipnx.cn/blog/detail/25012.html,不過這兩天西門老師在上Laravel操作數(shù)據(jù)庫課時,我聽到最多詞語是“掃表”、“慢查詢”、“數(shù)據(jù)庫優(yōu)化”,其實在前面課程時,和滅絕老師交流時也同樣考過我同樣的問題,就是發(fā)現(xiàn)數(shù)據(jù)庫慢查詢時如果定位和解決,當時我只是引用百度上某文中解析了,沒怎么太在意,目前實際開發(fā)項目數(shù)據(jù)庫也比較小,也沒遇到什么慢查詢,而這兩天課,西門老師講范圍查詢(大于或小于),聚合count等時提到掃表慢查詢以及數(shù)據(jù)庫優(yōu)化建議,我專門查詢學習了相關內容,才知道數(shù)據(jù)庫優(yōu)化的重要性,數(shù)據(jù)庫體量比較小還好說,一旦體量上到了百萬再不優(yōu)化,那數(shù)據(jù)庫操作再遇到高并發(fā)時將是非常糟糕的,而且不同于SQL語句和PDO操作是有固定語法的,數(shù)據(jù)庫優(yōu)化涉及范圍廣,也沒有固定的標準,只有根據(jù)情況來選擇存儲引擎、索引、SQL語句等,不過還是有些基礎的建議,我們可以參考。

二、Laravel8的數(shù)據(jù)庫DB類實現(xiàn)CURD操作

關于Laravel8的DB類操作數(shù)據(jù)庫都是參考官方文檔,建議大家多看,畢竟它是最權威的,其次就是源碼,我通過閱讀Laravel8的DB類的源碼,更加深刻理解DB實現(xiàn)的原理,也更清楚如何調用它們。官方要求數(shù)據(jù)庫及最低版本:MySQL 5.6、PostgreSQL 9.4、SQLite 3.8.8、SQL Server 2017,這里只介紹MySQL,其它可看官方文檔,沒有什么難度,訪問都已經(jīng)統(tǒng)一封裝了,差異已經(jīng)由Laravel和PDO解決了,還有我測試環(huán)境是Apache2.4.43+MySQL8.0.12+PHP8.1.0+Laravel8.5.7.

1、原生SQL語句

Laravel8的DB門面類為CURD操作提供了相應的方法:select,update,insert,delete 和 statement等,它定義源碼文件是vendor\laravel\framework\src\Illuminate\Database\Connection.php,它支持SQL語句和PDO的預處理,建議使用PDO的預處理,可防止SQL 注入和提高速度,這點同PDO的優(yōu)勢。

下面就是演示了查詢select、插入insert、更新update和刪除delete四個基本操作,其中select演示了SQL語句和預處理兩種,后三者全部是預處理,預處理語句中占位符可以是 問號?或命名綁定如:id ,第二個參數(shù)就是綁定的值,必須是數(shù)組 ,即使一個值也要是數(shù)組形式,詳細可看下面代碼或PHP官方文檔中PDO預處理的介紹。

  1. // 引入Laravel8內置的DB門面類
  2. use Illuminate\Support\Facades\DB;
  3. // 查詢Read
  4. private function select()
  5. {
  6. // SELECT * FROM cd_course_point where pid=11;
  7. // 原生SQL
  8. // return DB::select('select * from cd_course_point where pid=11');
  9. // 原生SQL支持預處理
  10. return DB::select('select * from cd_course_point where pid=?', [11]);
  11. }
  12. // 插入Create
  13. private function insert()
  14. {
  15. // INSERT INTO cd_course_point (point_name,pid,subject_id,sortid,status) VALUES ('測試',6,3,513,1);
  16. // 原生SQL支持預處理
  17. return DB::insert('INSERT INTO cd_course_point (point_name,pid,subject_id,sortid,status) VALUES (?,?,?,?,?)', ['測試', 6, 3, 513, 1]);
  18. }
  19. // 更新update
  20. private function update()
  21. {
  22. // 更新與刪除一定要加條件,否則將導航無法挽回的損失
  23. // 更新時若改變值是相同,則不會更新,返回影響記錄條數(shù)也為0
  24. //UPDATE cd_course_point SET point_name='測試更新' WHERE point_id=516;
  25. // 原生SQL支持預處理
  26. return DB::update('UPDATE cd_course_point SET point_name=? WHERE point_id=?', ['測試更新', 516]);
  27. }
  28. // 更新delete
  29. private function delete()
  30. {
  31. // 更新與刪除一定要加條件,否則將導航無法挽回的損失
  32. //DELETE FROM cd_course_point WHERE point_id=516;
  33. // 原生SQL支持預處理
  34. return DB::delete('DELETE FROM cd_course_point WHERE point_id=?', [516]);
  35. }

Laravel8的DB也提供了statement執(zhí)行普通語句和unprepared執(zhí)行非預處理語句,它們都存在SQL注入的危險,使用時要控制使用者范圍。代碼如下 :

  1. //刪除整個表
  2. DB::statement('drop table users');
  3. DB::unprepared('update users set votes = 100 where name = "Dries"');

2、查詢構造器之基本CURD

Laravel 的數(shù)據(jù)庫查詢構造器為創(chuàng)建和運行數(shù)據(jù)庫查詢提供了一個方便的接口。它可以用于支持大部分數(shù)據(jù)庫操作,并且在所有支持的數(shù)據(jù)庫系統(tǒng)上統(tǒng)一運行。Laravel 的查詢構造器使用 PDO 參數(shù)綁定的形式,保護您的應用程序免受 SQL 注入攻擊。因此不必清理因參數(shù)綁定而傳入的字符串。 它定義在vendor\laravel\framework\src\Illuminate\Database\Query\Builder.php

查詢構造器是從DB門面類的 table(‘表名’)方法來開始查詢。table 方法為給定的表返回一個查詢構造器實例,允許你在查詢上鏈式調用更多的約束,最后調用first()返回第一條記錄、get()返回所有記錄(Collection)、value(‘列名’)返回第一條記錄某列的值和plunk(‘列名‘)返回所有記錄某列的值(Collection),至于Collectioin可通過toArray()獲取數(shù)組。(在TP中table是直接指定表名,而name則是加上前綴的表名,Laravel8中DB的table方法等同于TP中name方法,Laravel8的前綴配置在config/database.php中prefix,自己可以進行測試)

查詢時一般建議需要什么那列數(shù)據(jù)就返回那列數(shù)據(jù),不要使用*返回所有列,返回某條記錄的指定列時可在first或get方法中指定,形式是數(shù)組,每列是字符串,可指定別名,如get(['point_id as id','point_name as name']),也可使用select方法指定列,如DB::table('cd_course_point')->where('pid',11)->select('point_id as id','point_name as name')->get()->toArray(),不過從源碼來角度分析,更推薦前者,主義更簡單直接。

  1. // 引入Laravel8內置的DB門面類
  2. use Illuminate\Support\Facades\DB;
  3. // 查詢構造器
  4. // 查詢Read
  5. private function select()
  6. {
  7. // SELECT * FROM cd_course_point where pid=11;
  8. // return DB::table('cd_course_point')->where('pid',11)->first();//第一條記錄
  9. // return DB::table('cd_course_point')->where('pid',11)->get()->toArray(); //所有記錄
  10. // return DB::table('cd_course_point')->where('pid',11)->value('point_name');//第一條記錄某列的值
  11. // return DB::table('cd_course_point')->where('pid', 11)->pluck('point_name')->toArray(); //所有記錄某列的值
  12. //查詢構造器指定列時可通過get或select獲取
  13. return DB::table('cd_course_point')->where('pid',11)->get(['point_id as id','point_name as name'])->toArray();
  14. // return DB::table('cd_course_point')->where('pid',11)->select('point_id as id','point_name as name')->get()->toArray();
  15. }
  16. // 插入Create
  17. private function insert()
  18. {
  19. // INSERT INTO cd_course_point (point_name,pid,subject_id,sortid,status) VALUES ('測試',6,3,513,1);
  20. $data['point_name'] = '測試而已';
  21. $data['pid'] = 6;
  22. $data['subject_id'] = 3;
  23. $data['sortid'] = '518';
  24. $data['status'] = 1;
  25. // return DB::table('cd_course_point')->insert($data);//若插入多條記錄
  26. return DB::table('cd_course_point')->insertGetId($data); //可返回插入的主鍵id,若是多條記錄則報錯
  27. }
  28. // 更新update
  29. private function update()
  30. {
  31. // 更新與刪除一定要加條件,否則將導航無法挽回的損失
  32. // 更新時若改變值是相同,則不會更新,返回影響記錄條數(shù)也為0
  33. //UPDATE cd_course_point SET point_name='測試更新' WHERE point_id=516;
  34. return DB::table('cd_course_point')->where('point_id', 518)->update(['point_name' => '測試構造器更新']);
  35. }
  36. // 更新delete
  37. private function delete()
  38. {
  39. // 更新與刪除一定要加條件,否則將導航無法挽回的損失
  40. //DELETE FROM cd_course_point WHERE point_id=516;
  41. return DB::table('cd_course_point')->where('point_id', 516)->delete();
  42. // 若是delete清除表所有數(shù)據(jù),MyISAM是清除表再新建表,而InnoDB則是一條條記錄刪除
  43. // return DB::table('cd_course_point')->truncate();//清空整個表并重置所有的自增 ID 為 0
  44. }

重要提醒:
1.insertGetId返回插入的數(shù)據(jù)庫主鍵ID,只限于插入一條記錄,若是多條記錄則報錯,而insert支持一條記錄或多條記錄插入。
2.update或delete操作必須要有條件,否則在其實項目中可能導致無法挽回的損失,一定要牢記
3.若是清空整個表建議是使用truncate,尤其是InnoDB存儲引擎時,若是使用delete將是掃表刪除,而MyISAM若是delete則是先刪除表再新建表,比較塊。

3、查詢構造器之聚合

在查詢中我們經(jīng)常需要統(tǒng)計、求最大、最小、平均和和,Laravel8的DB也為我們提供了相應的方法,比如count,max,min,avg,還有 sum。你可以在構造查詢后調用任何方法,使用比較簡單,如下面代碼

  1. private function count(){
  2. // select count(*) from cd_course_point where pid=11
  3. return DB::table('cd_course_point')->where('pid',11)->count();
  4. }

還有官方文檔中提供的:

  1. $price = DB::table('orders')->max('price');
  2. $price = DB::table('orders') ->where('finalized', 1) ->avg('price');

建議: 在數(shù)據(jù)庫查詢時,能用聚合就用聚合,它可減少數(shù)據(jù)庫與服務端交換的數(shù)據(jù)量,數(shù)據(jù)庫訪問優(yōu)化策略之一。對于需要聚合查詢的表,存儲引擎則建議是MyISAM,至于為什么在后面優(yōu)化建議中有介紹。

在判斷記錄是否存在時我們常用count方法來統(tǒng)計,其實Laravel8的DB已經(jīng)提供了更高效的方法exists或doesntExist。

  1. return DB::table('orders')->where('finalized', 1)->exists();
  2. return DB::table('orders')->where('finalized', 1)->doesntExist();

5、查詢構造器之擴展where

所謂擴展where就是將常用的where操作,如or、between、in、NUll、子查詢或列查詢都提供了封裝方法,如orWhere、whereIn、whereBetween等等,更詳細可參考官方文檔。

  1. // 小于+大于與between
  2. return DB::table('cd_course_point')->where('point_id','>',100)->where('point_id','<',150)->count();
  3. return DB::table('cd_course_point')->whereBetween('point_id',[100,150])->count();
  4. //or與in
  5. return DB::table('cd_course_point')->orWhere('point_id',23)->orWhere('point_id',45)->get()->toArray();
  6. return DB::table('cd_course_point')->whereIn('point_id',[23,45,56])->get()->toArray();

4、查詢構造器之where認識

老師在演示where方法時只演示了等值、大于或小于等判斷,而在我學習數(shù)據(jù)庫時我想演示like模糊匹配、find_in_set精確匹配等操作,并未找到對應擴展的where,難度它不支持這些操作,必須要用原生SQL語句,當然原生SQL語句是可以實現(xiàn)的。在官方文檔中我看到where('name', 'like', 'T%'),那么它到底哪些操作符呢?官方文檔并未給出答案,帶著疑問,我查詢了vendor\laravel\framework\src\Illuminate\Database\Query\Builder.php中源碼,它的內容是:

  1. public $operators = [
  2. '=', '<', '>', '<=', '>=', '<>', '!=', '<=>',
  3. 'like', 'like binary', 'not like', 'ilike',
  4. '&', '|', '^', '<<', '>>',
  5. 'rlike', 'not rlike', 'regexp', 'not regexp',
  6. '~', '~*', '!~', '!~*', 'similar to',
  7. 'not similar to', 'not ilike', '~~*', '!~~*',
  8. ];

從中我們發(fā)現(xiàn)了like模糊查詢,還有regexp正則,現(xiàn)在算是比較理解where的操作符了,現(xiàn)在是不是發(fā)現(xiàn)閱讀源碼是不是學習的一種好方法。

6、查詢構造器之where原生方法

我在項目中經(jīng)常使用find_in_set,在擴展where中沒見到,本以為在上面where中可能見到,發(fā)現(xiàn)也沒有,最后在網(wǎng)上查詢了,才知道它根本沒實現(xiàn)find_in_set方法的封裝,只能能過原生語句或原生方法來實現(xiàn),原生語句前面已經(jīng)講過了,這時重要提下原生方法,即方法名中帶有raw關鍵詞的方法,它等同于前面的SQL語句,不過突出 條件部分 。如find_in_set的實現(xiàn)語句是

  1. return DB::table('cd_course_point')->where('point_name','like','%字母%')->get()->toArray();
  2. return DB::table('cd_course_point')->whereRaw('find_in_set(?,point_name)',['字母'])->get()->toArray();

7、查詢構造器之join聯(lián)表

Laravel的DB提供了常規(guī)的join(內邊),leftJoin(左連),rightJoin(右連)和crossJoin(交叉連接)四個基本的聯(lián)表,操作也不難理解,具體可參考TP中語法

  1. $users = DB::table('users')
  2. ->join('contacts', 'users.id', '=', 'contacts.user_id')
  3. ->join('orders', 'users.id', '=', 'orders.user_id')
  4. ->select('users.*', 'contacts.phone', 'orders.price')
  5. ->get();
  6. $users = DB::table('users') ->leftJoin('posts', 'users.id', '=', 'posts.user_id') ->get();
  7. $users = DB::table('users') ->rightJoin('posts', 'users.id', '=', 'posts.user_id') ->get();
  8. $sizes = DB::table('sizes') ->crossJoin('colors') ->get();

高級 Join 語句,你可以指定更高級的 join 語句。比如傳遞一個閉包作為 join 方法的第二個參數(shù)。此閉包接收一個 JoinClause 對象,從而指定 join 語句中指定的約束

  1. DB::table('users')
  2. ->join('contacts', function ($join) {
  3. $join->on('users.id', '=', 'contacts.user_id')
  4. ->where('contacts.user_id', '>', 5);
  5. })->get();

上面是比較詳細介紹了Laravel的數(shù)據(jù)庫操作知識,在老師基礎上加上我對官方文檔和源碼的理解,分為七個部分內容,不是很全面,如where中條件使用閉包函數(shù),可實現(xiàn)更復雜的條件,可參考官方文檔或TP6中閉包函數(shù)使用,但涉及操作中幾個方面,基本就是我們日常需要的了。

三、數(shù)據(jù)庫的訪問優(yōu)化建議

說實在話,只是老師授課時強調了,在百度上查詢學習了下,對于數(shù)據(jù)庫算是基本的優(yōu)化建議了。

1、SQL語句的選擇

能用聚合時就用聚合,需要什么字段就獲取什么字段

減少數(shù)據(jù)庫與服務端之間的交換數(shù)據(jù)量,減少服務端某請求占用數(shù)據(jù)庫連接的時間,從而提高請求的響應速度,提高數(shù)據(jù)庫連接的效率。

減少范圍大于、小于、or、in或like等慢查詢(全表掃描),多使用等值、between和find_in_set查詢代替

慢查詢是數(shù)據(jù)庫訪問優(yōu)化最大的敵人,掃表是最典型的慢查詢表現(xiàn),一般現(xiàn)在云服務端掃描到慢查詢都會及時提醒,當然也可自行開啟MySQL內置的慢日志功能,開啟方法在后面有介紹。

減少使用join進行跨數(shù)據(jù)庫或服務器的查詢,本數(shù)據(jù)庫join查表不要超過3個

上面是阿里程序員建議表中一條,因為join聯(lián)表查詢是比較復雜的,優(yōu)化不僅要降低慢查詢次數(shù),也要盡量降低復雜度,提高查詢效率。

2、存儲引擎的選擇

MySQL存儲引擎主流有兩個:MyISAM和InnoDB,MySQL 5.1之前的版本中,默認的搜索引擎是MyISAM,從MySQL 5.5之后的版本中,默認的搜索引擎變更為InnoDB。

MyISAM存儲引擎的特點是:表級鎖、不支持事務和全文索引,適合一些CMS內容管理系統(tǒng)作為后臺數(shù)據(jù)庫使用,但是使用大并發(fā)、重負荷生產(chǎn)系統(tǒng)上,表鎖結構的特性就顯得力不從心;

myisam

InnoDB存儲引擎的特點是:行級鎖、事務安全(ACID兼容)、支持外鍵、不支持FULLTEXT類型的索引(5.6.4以后版本開始支持FULLTEXT類型的索引)。InnoDB存儲引擎提供了具有提交、回滾和崩潰恢復能力的事務安全存儲引擎。InnoDB是為處理巨大量時擁有最大性能而設計的。它的CPU效率可能是任何其他基于磁盤的關系數(shù)據(jù)庫引擎所不能匹敵的。

innodb

注意: InnoDB表的行鎖也不是絕對的,假如在執(zhí)行一個SQL語句時MySQL不能確定要掃描的范圍,InnoDB表同樣會鎖全表,例如update table set num=1 where name like “a%”。

MyISAM與InnoDB構成上的區(qū)別:
MyISAM在磁盤上存儲成三個文件:

第一個文件的名字以表的名字開始,擴展名指出文件類型,.frm文件存儲表定義。
第二個文件是數(shù)據(jù)文件,其擴展名為.MYD (MYData)。
第三個文件是索引文件,其擴展名是.MYI (MYIndex)。

基于磁盤的資源是InnoDB表空間數(shù)據(jù)文件和它的日志文件,InnoDB 表的 大小只受限于操作系統(tǒng)文件的大小,一般為 2GB。

如何選擇:

  1. InnoDB支持事務,MyISAM不支持,對于InnoDB每一條SQL語言都默認封裝成事務,自動提交,這樣會影響速度,所以最好把多條SQL語言放在begin和commit之間,組成一個事務;
  2. InnoDB支持外鍵,而MyISAM不支持。對一個包含外鍵的InnoDB表轉為MYISAM會失?。?/li>
  3. InnoDB是聚集索引,數(shù)據(jù)文件是和索引綁在一起的,必須要有主鍵,通過主鍵索引效率很高。但是輔助索引需要兩次查詢,先查詢到主鍵,然后再通過主鍵查詢到數(shù)據(jù)。因此,主鍵不應該過大,因為主鍵太大,其他索引也都會很大。而MyISAM是非聚集索引,數(shù)據(jù)文件是分離的,索引保存的是數(shù)據(jù)文件的指針。主鍵索引和輔助索引是獨立的。
  4. InnoDB不保存表的具體行數(shù),執(zhí)行select count(*) from table時需要全表掃描。而MyISAM用一個變量保存了整個表的行數(shù),執(zhí)行上述語句時只需要讀出該變量即可,速度很快;
  5. Innodb不支持全文索引,而MyISAM支持全文索引,查詢效率上MyISAM要高;
  6. 是否要支持事務,如果要請選擇innodb,如果不需要可以考慮MyISAM;
  7. 如果表中絕大多數(shù)都只是讀查詢,可以考慮MyISAM,如果既有讀寫也挺頻繁,請使用InnoDB。
  8. 系統(tǒng)奔潰后,MyISAM恢復起來更困難,能否接受;
  9. MySQL5.5版本開始Innodb已經(jīng)成為Mysql的默認引擎(之前是MyISAM),說明其優(yōu)勢是有目共睹的,如果你不知道用什么,那就用InnoDB,至少不會差。

3、索引的選擇

一般的應用系統(tǒng),讀寫比例在10:1左右,而且插入操作和一般的更新操作很少出現(xiàn)性能問題,在生產(chǎn)環(huán)境中,我們遇到最多的,也是最容易出問題的,還是一些復雜的查詢操作。索引在MySQL中也叫做“鍵”,是存儲引擎用于快速找到記錄的一種數(shù)據(jù)結構。索引對于良好的性能非常關鍵,尤其是當表中的數(shù)據(jù)量越來越大時,索引對于性能的影響愈發(fā)重要。索引優(yōu)化應該是對查詢性能優(yōu)化最有效的手段了。索引能夠輕易將查詢性能提高好幾個數(shù)量級。索引相當于字典的音序表,如果要查某個字,如果不使用音序表,則需要從幾百頁中逐頁去查。

索引建議:
1.普通索引index :加速查找
2.唯一索引
主鍵索引:primary key :加速查找+約束(不為空且唯一)
唯一索引:unique:加速查找+約束 (唯一)
3.聯(lián)合索引
-primary key(id,name):聯(lián)合主鍵索引
-unique(id,name):聯(lián)合唯一索引
-index(id,name):聯(lián)合普通索引
4.全文索引fulltext :用于搜索很長一篇文章的時候,效果最好。
5.空間索引spatial :了解就好,幾乎不用

舉個例子來說,比如你在為某商場做一個會員卡的系統(tǒng), 這個系統(tǒng)有一個會員表,有下列字段:
會員編號 INT、會員姓名 VARCHAR(10)、會員身份證號碼 VARCHAR(18)、會員電話 VARCHAR(10)、會員住址 VARCHAR(50)和會員備注信息 TEXT

索引案例:

  • 會員編號,作為主鍵,使用 PRIMARY
  • 會員姓名 如果要建索引的話,那么就是普通的 INDEX
  • 會員身份證號碼 如果要建索引的話,那么可以選擇 UNIQUE(唯一的,不允許重復),除此之外還有全文索引,即FULLTEXT
  • 會員備注信息 , 如果需要建索引的話,可以選擇全文搜索。用于搜索很長一篇文章的時候,效果最好。用在比較短的文本,如果就一兩行字的,普通的 INDEX 也可以。
  • 但其實對于全文搜索,我們并不會使用MySQL自帶的該索引,而是會選擇第三方軟件如Sphinx,專門來做全文搜索。Laravel也有專門全文搜索類 Scout 全文搜索

以上主要參考https://www.cnblogs.com/bypp/p/7755307.html。

Sphinx高性能SQL全文檢索引擎:Sphinx是一款基于SQL的高性能全文檢索引擎,Sphinx的性能在眾多全文檢索引擎中也是數(shù)一數(shù)二的,利用Sphinx,我們可以完成比數(shù)據(jù)庫本身更專業(yè)的搜索功能,而且可以有很多針對性的性能優(yōu)化。

  • 快速創(chuàng)建索引:3分鐘左右即可創(chuàng)建近100萬條記錄的索引,并且采用了增量索引的方式,重建索引非常迅速。
  • 閃電般的檢索速度:盡管是1千萬條的大數(shù)據(jù)量,查詢數(shù)據(jù)的速度也在毫秒級以上,2-4G的文本量中平均查詢速度不到0.1秒。
  • 為很多腳本語言設計了檢索API,如PHP,Python,Perl,Ruby等,因此你可以在大部分編程應用中很方便地調用Sphinx的相關接口。
  • 為MySQL設計了一個存儲引擎插件,因此如果你在MySQL上使用Sphinx,那簡直就方便到家了。
  • 支持分布式搜索,可以橫向擴展系統(tǒng)性能。

關于Sphinx學習不是本文的內容了,可以專門到它官方網(wǎng)站進行學習。

4、慢查詢定位

在默認的情況下,MySQL認為10秒才是一個慢查詢,用存儲函數(shù)構建一個數(shù)據(jù)表(1000萬)

如何定位慢查詢:

  • a.根據(jù)慢日志定位慢查詢sql: SHOW VARIABLES LIKE ‘%query%’ 查詢慢日志相關信息
    low01
    slow_query_log 默認是off關閉的,使用時,需要改為on 打開      
    slow_query_log_file 記錄的是慢日志的記錄文件
    long_query_time 默認是10S,每次執(zhí)行的sql達到這個時長,就會被記錄
    SHOW STATUS LIKE ‘%slow_queries%’ 查看慢查詢狀態(tài)
    low02
    Slow_queries 記錄的是慢查詢數(shù)量 當有一條sql執(zhí)行一次比較慢時,這個vlue就是1 (記錄的是本次會話的慢sql條數(shù))

  • b.使用explain等工具分析sql: 在要執(zhí)行的sql前加上explain 例如:EXPLAIN SELECT menu_name FROM t_sys_menu ORDER BY menu_id DESC;
    low03
    接著看explain的關鍵字段type,如果發(fā)現(xiàn)type的值是最后兩個中的其中一個時,證明語句需要優(yōu)化了。
    low04
    再看字段extra
    low05

 c.修改sql或者盡量讓sql走索引,mysql查詢優(yōu)化器會根據(jù)具體情況自己判斷走哪個索引,不一定是走主鍵(explain中的key可以看到走的哪個key)具體情況根據(jù)具體情況來定,當你要強制執(zhí)行走某一個key時:在查詢的最后加上 force index(primary); 強制走主鍵的。

開啟慢查詢

有兩種方式可以開啟慢查詢:修改配置文件和設置全局變量

方式一:需要修改配置文件 my.ini,在[mysqld]段落中加入如下參數(shù):

  1. [mysqld]
  2. log_output='FILE,TABLE'
  3. slow_query_log='ON'
  4. long_query_time=0.001

然后需要重啟 MySQL 才可以生效,命令為 service mysqld restart

方式二:無需重啟即可生效,但是重啟會導致設置失效,設置的命令如下所示:

  1. SET GLOBAL slow_query_log = 'ON';
  2. SET GLOBAL log_output = 'FILE,TABLE';
  3. SET GLOBAL long_query_time = 0.001;

這樣就可以將慢查詢日志同時記錄在文件以及 mysql.slow_log 表中。通過第二種方式開啟慢查詢日志,然后使用全表查詢語句SELECT * FROM user,然后再查詢慢查詢日志:SELECT * FROM mysql.slow_log,可以發(fā)現(xiàn)其中有這樣一條記錄:

low06

其中,start_time 為執(zhí)行時間,user_host 為用戶的主機名,query_time 為查詢所花費的時間,lock_time 為該查詢使用鎖的時間,rows_sent 為這條查詢返回了多少數(shù)據(jù)給客戶端,rows_examined 表示這條語句掃描了多少行,db 為數(shù)據(jù)庫,sql_text 為這條 SQL,thread_id 為執(zhí)行這條查詢的線程 id。這樣我們就可以通過 slow_log 表的數(shù)據(jù)進行分析,然后對 SQL 進行調優(yōu)了。

以上是通過 Table 來進行分析的,下面來通過文件的慢查詢是怎么樣的。

如果不知道文件保存在哪里,可以使用 SHOW VARIABLES LIKE ‘%slow_query_log_file%’ 來查看文件保存位置,打開慢查詢日志文件,可以看出每五行表示一個慢 SQL,這樣查看比較費事,可以使用一些工具來查看。

low07

5、Mysql慢查詢優(yōu)化建議

1、日期大小的比較,傳到xml中的日期格式要符合’yyyy-MM-dd’,這樣才能走索引,如:’yyyy’改為’yyyy-MM-dd’,’yyyy-MM’改為’yyyy-MM-dd’【這樣MYSQL會轉換為日期類型】

2、條件語句中無論是等于、還是大于小于,WHERE左側的條件查詢字段不要使用函數(shù)或表達式或數(shù)學運算

3、WHERE條件語句嘗試著調整字段的順序提升查詢速度,如把索引字段放在最前面、把查詢命中率高的字段置前等

4、保證優(yōu)化SQL前后其查詢結果是一致的

5、在查詢的時候通過將EXPLAIN命令寫在查詢語句前,測試語句是否有走索引【具體用法百度】

6、禁止使用SELECT * FROM操作,應只返回需要的字段,不需要的字段不要返回

7、可以嘗試分解復雜的查詢,在應用層面進行表關聯(lián),以此代替SQL層面的表關聯(lián)

8、WHERE子句和ORDER BY子句涉及到的列建索引

9、避免在WHERE子句中對字段進行NULL判斷【可以對表字段改造一下,字符串型字段默認值設置為空字符串,數(shù)字型字段默認值設置為0,日期型字段默認值設置為1990-01-01等】

10、避免在WHERE子句中使用!=或<>操作符

11、避免在WHERE子句中使用OR操作符

12、BETWEEN AND代替IN

13、LIKE ‘%abc%’不會走索引,而LIKE ‘a(chǎn)bc%’會走索引

14、避免對字段進行表達式操作

15、避免對字段進行函數(shù)操作

16、GROUP BY操作默認會對GROUP BY后面的字段進行排序,如果你的程序不需要排序,可在GROUP BY語句后面加上ORDER BY NULL去除排序

17、如果是數(shù)值型字段,則盡量設計為數(shù)值型字段,不要為了方便、為了偷懶而給后面維護的同事埋坑

18、表中所有字段設計為NOT NULL

19、返回條數(shù)固定時,用LIMIT語句限制返回記錄的條數(shù),如只需要一條記錄,或肯定只有一條記錄符合條件,那建議加上LIMIT 1

20、對于枚舉類型的字段【即有固定羅列值的字段】,建議使用ENUM而不是VARCHAR,如性別、星期、類型、類別等

21、對于存IP地址的字段設計為成UNSIGNED INT型

22、避免在SQL中使用NOW()、CURDATE()、RAND()函數(shù)【因為這種方式會導致MYSQL無法使用SQL緩存】,可以轉化為通過傳入?yún)?shù)的方式

23、對于統(tǒng)計類的查詢【如查詢連續(xù)幾個月的數(shù)據(jù)總量,或查詢同比、環(huán)比等】,可以通過定時查詢并統(tǒng)計到統(tǒng)計表的方式提高查詢速度

批改老師:天蓬老師天蓬老師

批改狀態(tài):合格

老師批語:
本博文版權歸博主所有,轉載請注明地址!如有侵權、違法,請聯(lián)系admin@php.cn舉報處理!
全部評論 文明上網(wǎng)理性發(fā)言,請遵守新聞評論服務協(xié)議
0條評論
作者最新博文
關于我們 免責申明 意見反饋 講師合作 廣告合作 最新更新
php中文網(wǎng):公益在線php培訓,幫助PHP學習者快速成長!
關注服務號 技術交流群
PHP中文網(wǎng)訂閱號
每天精選資源文章推送
PHP中文網(wǎng)APP
隨時隨地碎片化學習
PHP中文網(wǎng)抖音號
發(fā)現(xiàn)有趣的

Copyright 2014-2025 http://ipnx.cn/ All Rights Reserved | php.cn | 湘ICP備2023035733號

  • 登錄PHP中文網(wǎng),和優(yōu)秀的人一起學習!
    全站2000+教程免費學