MySQL常見的8種SQL錯誤用法

来源:https://www.cnblogs.com/weilingfeng/archive/2019/08/24/11404487.html
-Advertisement-
Play Games

MySQL常見的8種SQL錯誤用法 前言 MySQL在2016年仍然保持強勁的資料庫流行度增長趨勢。越來越多的客戶將自己的應用建立在MySQL資料庫之上,甚至是從Oracle遷移到MySQL上來。但也存在部分客戶在使用MySQL資料庫的過程中遇到一些比如響應時間慢,CPU打滿等情況。 阿裡雲RDS專 ...


MySQL常見的8種SQL錯誤用法

前言

MySQL在2016年仍然保持強勁的資料庫流行度增長趨勢。越來越多的客戶將自己的應用建立在MySQL資料庫之上,甚至是從Oracle遷移到MySQL上來。但也存在部分客戶在使用MySQL資料庫的過程中遇到一些比如響應時間慢,CPU打滿等情況。

阿裡雲RDS專家服務團隊幫助雲上客戶解決過很多緊急問題。現將《ApsaraDB專家診斷報告》中出現的部分常見SQL問題總結如下,供大家參考。

1、LIMIT 語句

分頁查詢是最常用的場景之一,但也通常也是最容易出問題的地方。

比如對於下麵簡單的語句,一般 DBA 想到的辦法是在 type, name, create_time 欄位上加組合索引。這樣條件排序都能有效的利用到索引,性能迅速提升。

 

 

 

SELECT * 
FROM   operation 
WHERE  type = 'SQLStats' 
       AND name = 'SlowLog' 
ORDER  BY create_time 
LIMIT  1000, 10;複製代碼

 

好吧,可能90%以上的 DBA 解決該問題就到此為止。

但當 LIMIT 子句變成 “LIMIT 1000000,10” 時,程式員仍然會抱怨:我只取10條記錄為什麼還是慢?

要知道資料庫也並不知道第1000000條記錄從什麼地方開始,即使有索引也需要從頭計算一次。出現這種性能問題,多數情形下是程式員偷懶了。

在前端數據瀏覽翻頁,或者大數據分批導出等場景下,是可以將上一頁的最大值當成參數作為查詢條件的。SQL 重新設計如下:

 

 

 

SELECT   * 
FROM     operation 
WHERE    type = 'SQLStats' 
AND      name = 'SlowLog' 
AND      create_time > '2017-03-16 14:00:00' 
ORDER BY create_time limit 10;複製代碼

 

在新設計下查詢時間基本固定,不會隨著數據量的增長而發生變化。

2、隱式轉換

SQL語句中查詢變數和欄位定義類型不匹配是另一個常見的錯誤。比如下麵的語句:

 

 

 

mysql> explain extended SELECT * 
     > FROM   my_balance b 
     > WHERE  b.bpn = 14000000123 
     >       AND b.isverified IS NULL ;
mysql> show warnings;
| Warning | 1739 | Cannot use ref access on index 'bpn' due to type or collation conversion on field 'bpn'複製代碼

 

其中欄位 bpn 的定義為 varchar(20),MySQL 的策略是將字元串轉換為數字之後再比較。函數作用於表欄位,索引失效。

上述情況可能是應用程式框架自動填入的參數,而不是程式員的原意。現在應用框架很多很繁雜,使用方便的同時也小心它可能給自己挖坑。

3、關聯更新、刪除

雖然 MySQL5.6 引入了物化特性,但需要特別註意它目前僅僅針對查詢語句的優化。對於更新或刪除需要手工重寫成 JOIN。

比如下麵 UPDATE 語句,MySQL 實際執行的是迴圈/嵌套子查詢(DEPENDENT SUBQUERY),其執行時間可想而知。

 

 

 

UPDATE operation o 
SET    status = 'applying' 
WHERE  o.id IN (SELECT id 
                FROM   (SELECT o.id, 
                               o.status 
                        FROM   operation o 
                        WHERE  o.group = 123 
                               AND o.status NOT IN ( 'done' ) 
                        ORDER  BY o.parent, 
                                  o.id 
                        LIMIT  1) t);複製代碼

 

執行計劃:

 

 

 

+----+--------------------+-------+-------+---------------+---------+---------+-------+------+-----------------------------------------------------+
| id | select_type        | table | type  | possible_keys | key     | key_len | ref   | rows | Extra                                               |
+----+--------------------+-------+-------+---------------+---------+---------+-------+------+-----------------------------------------------------+
| 1  | PRIMARY            | o     | index |               | PRIMARY | 8       |       | 24   | Using where; Using temporary                        |
| 2  | DEPENDENT SUBQUERY |       |       |               |         |         |       |      | Impossible WHERE noticed after reading const tables |
| 3  | DERIVED            | o     | ref   | idx_2,idx_5   | idx_5   | 8       | const | 1    | Using where; Using filesort                         |
+----+--------------------+-------+-------+---------------+---------+---------+-------+------+-----------------------------------------------------+複製代碼

 

重寫為 JOIN 之後,子查詢的選擇模式從 DEPENDENT SUBQUERY 變成 DERIVED,執行速度大大加快,從7秒降低到2毫秒。

 

 

 

UPDATE operation o 
       JOIN  (SELECT o.id, 
                            o.status 
                     FROM   operation o 
                     WHERE  o.group = 123 
                            AND o.status NOT IN ( 'done' ) 
                     ORDER  BY o.parent, 
                               o.id 
                     LIMIT  1) t
         ON o.id = t.id 
SET    status = 'applying' 複製代碼

 

執行計劃簡化為:

 

 

 

+----+-------------+-------+------+---------------+-------+---------+-------+------+-----------------------------------------------------+
| id | select_type | table | type | possible_keys | key   | key_len | ref   | rows | Extra                                               |
+----+-------------+-------+------+---------------+-------+---------+-------+------+-----------------------------------------------------+
| 1  | PRIMARY     |       |      |               |       |         |       |      | Impossible WHERE noticed after reading const tables |
| 2  | DERIVED     | o     | ref  | idx_2,idx_5   | idx_5 | 8       | const | 1    | Using where; Using filesort                         |
+----+-------------+-------+------+---------------+-------+---------+-------+------+-----------------------------------------------------+複製代碼

 

4、混合排序

MySQL 不能利用索引進行混合排序。但在某些場景,還是有機會使用特殊方法提升性能的。

 

 

 

SELECT * 
FROM   my_order o 
       INNER JOIN my_appraise a ON a.orderid = o.id 
ORDER  BY a.is_reply ASC, 
          a.appraise_time DESC 
LIMIT  0, 20 複製代碼

 

執行計劃顯示為全表掃描:

 

 

 

+----+-------------+-------+--------+-------------+---------+---------+---------------+---------+-+
| id | select_type | table | type   | possible_keys     | key     | key_len | ref      | rows    | Extra    
+----+-------------+-------+--------+-------------+---------+---------+---------------+---------+-+
|  1 | SIMPLE      | a     | ALL    | idx_orderid | NULL    | NULL    | NULL    | 1967647 | Using filesort |
|  1 | SIMPLE      | o     | eq_ref | PRIMARY     | PRIMARY | 122     | a.orderid |       1 | NULL           |
+----+-------------+-------+--------+---------+---------+---------+-----------------+---------+-+複製代碼

 

由於 is_reply 只有0和1兩種狀態,我們按照下麵的方法重寫後,執行時間從1.58秒降低到2毫秒。

 

 

 

SELECT * 
FROM   ((SELECT *
         FROM   my_order o 
                INNER JOIN my_appraise a 
                        ON a.orderid = o.id 
                           AND is_reply = 0 
         ORDER  BY appraise_time DESC 
         LIMIT  0, 20) 
        UNION ALL 
        (SELECT *
         FROM   my_order o 
                INNER JOIN my_appraise a 
                        ON a.orderid = o.id 
                           AND is_reply = 1 
         ORDER  BY appraise_time DESC 
         LIMIT  0, 20)) t 
ORDER  BY  is_reply ASC, 
          appraisetime DESC 
LIMIT  20;複製代碼

 

5、EXISTS語句

MySQL 對待 EXISTS 子句時,仍然採用嵌套子查詢的執行方式。如下麵的 SQL 語句:

 

 

 

SELECT *
FROM   my_neighbor n 
       LEFT JOIN my_neighbor_apply sra 
              ON n.id = sra.neighbor_id 
                 AND sra.user_id = 'xxx' 
WHERE  n.topic_status < 4 
       AND EXISTS(SELECT 1 
                  FROM   message_info m 
                  WHERE  n.id = m.neighbor_id 
                         AND m.inuser = 'xxx') 
       AND n.topic_type <> 5 複製代碼

 

執行計劃為:

 

 

 

+----+--------------------+-------+------+-----+------------------------------------------+---------+-------+---------+ -----+
| id | select_type        | table | type | possible_keys     | key   | key_len | ref   | rows    | Extra   |
+----+--------------------+-------+------+ -----+------------------------------------------+---------+-------+---------+ -----+
|  1 | PRIMARY            | n     | ALL  |  | NULL     | NULL    | NULL  | 1086041 | Using where                   |
|  1 | PRIMARY            | sra   | ref  |  | idx_user_id | 123     | const |       1 | Using where          |
|  2 | DEPENDENT SUBQUERY | m     | ref  |  | idx_message_info   | 122     | const |       1 | Using index condition; Using where |
+----+--------------------+-------+------+ -----+------------------------------------------+---------+-------+---------+ -----+複製代碼

 

去掉 exists 更改為 join,能夠避免嵌套子查詢,將執行時間從1.93秒降低為1毫秒。

 

 

 

SELECT *
FROM   my_neighbor n 
       INNER JOIN message_info m 
               ON n.id = m.neighbor_id 
                  AND m.inuser = 'xxx' 
       LEFT JOIN my_neighbor_apply sra 
              ON n.id = sra.neighbor_id 
                 AND sra.user_id = 'xxx' 
WHERE  n.topic_status < 4 
       AND n.topic_type <> 5 複製代碼

 

新的執行計劃:

 

 

 

+----+-------------+-------+--------+ -----+------------------------------------------+---------+ -----+------+ -----+
| id | select_type | table | type   | possible_keys     | key       | key_len | ref   | rows | Extra                 |
+----+-------------+-------+--------+ -----+------------------------------------------+---------+ -----+------+ -----+
|  1 | SIMPLE      | m     | ref    | | idx_message_info   | 122     | const    |    1 | Using index condition |
|  1 | SIMPLE      | n     | eq_ref | | PRIMARY   | 122     | ighbor_id |    1 | Using where      |
|  1 | SIMPLE      | sra   | ref    | | idx_user_id | 123     | const     |    1 | Using where           |
+----+-------------+-------+--------+ -----+------------------------------------------+---------+ -----+------+ -----+複製代碼

 

6、條件下推

外部查詢條件不能夠下推到複雜的視圖或子查詢的情況有:

  • 聚合子查詢;

  • 含有 LIMIT 的子查詢;

  • UNION 或 UNION ALL 子查詢;

  • 輸出欄位中的子查詢;

如下麵的語句,從執行計劃可以看出其條件作用於聚合子查詢之後:

 

 

 

SELECT * 
FROM   (SELECT target, 
               Count(*) 
        FROM   operation 
        GROUP  BY target) t 
WHERE  target = 'rm-xxxx'複製代碼

 

 

 

+----+-------------+------------+-------+---------------+-------------+---------+-------+------+-------------+
| id | select_type | table      | type  | possible_keys | key         | key_len | ref   | rows | Extra       |
+----+-------------+------------+-------+---------------+-------------+---------+-------+------+-------------+
|
1
| PRIMARY     |
 <derived2> 
| ref   |
 <auto_key
0
>   
| <auto_key0> |
514
| const |
2
| Using where |
|  2 | DERIVED     | operation  | index | idx_4         | idx_4       | 519     | NULL  |   20 | Using index |
+----+-------------+------------+-------+---------------+-------------+---------+-------+------+-------------+複製代碼

 

確定從語義上查詢條件可以直接下推後,重寫如下:

 

 

 

SELECT target, 
       Count(*) 
FROM   operation 
WHERE  target = 'rm-xxxx' 
GROUP  BY target複製代碼

 

執行計劃變為:

 

 

 

+----+-------------+-----------+------+---------------+-------+---------+-------+------+--------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+------+---------------+-------+---------+-------+------+--------------------+
| 1 | SIMPLE | operation | ref | idx_4 | idx_4 | 514 | const | 1 | Using where; Using index |
+----+-------------+-----------+------+---------------+-------+---------+-------+------+--------------------+複製代碼

 

關於 MySQL 外部條件不能下推的詳細解釋說明請參考文章:

http://mysql.taobao.org/monthly/2016/07/08

7、提前縮小範圍

先上初始 SQL 語句:

 

 

 

SELECT * 
FROM   my_order o 
       LEFT JOIN my_userinfo u 
              ON o.uid = u.uid
       LEFT JOIN my_productinfo p 
              ON o.pid = p.pid 
WHERE  ( o.display = 0 ) 
       AND ( o.ostaus = 1 ) 
ORDER  BY o.selltime DESC 
LIMIT  0, 15 複製代碼

 

該SQL語句原意是:先做一系列的左連接,然後排序取前15條記錄。從執行計劃也可以看出,最後一步估算排序記錄數為90萬,時間消耗為12秒。

 

 

 

+----+-------------+-------+--------+---------------+---------+---------+-----------------+--------+----------------------------------------------------+
| id | select_type | table | type   | possible_keys | key     | key_len | ref             | rows   | Extra                                              |
+----+-------------+-------+--------+---------------+---------+---------+-----------------+--------+----------------------------------------------------+
|  1 | SIMPLE      | o     | ALL    | NULL          | NULL    | NULL    | NULL            | 909119 | Using where; Using temporary; Using filesort       |
|  1 | SIMPLE      | u     | eq_ref | PRIMARY       | PRIMARY | 4       | o.uid |      1 | NULL                                               |
|  1 | SIMPLE      | p     | ALL    | PRIMARY       | NULL    | NULL    | NULL            |      6 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+-------+--------+---------------+---------+---------+-----------------+--------+----------------------------------------------------+複製代碼

 

由於最後 WHERE 條件以及排序均針對最左主表,因此可以先對 my_order 排序提前縮小數據量再做左連接。SQL 重寫後如下,執行時間縮小為1毫秒左右。

 

 

 

SELECT * 
FROM (
SELECT * 
FROM   my_order o 
WHERE  ( o.display = 0 ) 
       AND ( o.ostaus = 1 ) 
ORDER  BY o.selltime DESC 
LIMIT  0, 15
) o 
     LEFT JOIN my_userinfo u 
              ON o.uid = u.uid 
     LEFT JOIN my_productinfo p 
              ON o.pid = p.pid 
ORDER BY  o.selltime DESC
limit 0, 15複製代碼

 

再檢查執行計劃:子查詢物化後(select_type=DERIVED)參與 JOIN。雖然估算行掃描仍然為90萬,但是利用了索引以及 LIMIT 子句後,實際執行時間變得很小。

 

 

 

+----+-------------+------------+--------+---------------+---------+---------+-------+--------+----------------------------------------------------+
| id | select_type | table      | type   | possible_keys | key     | key_len | ref   | rows   | Extra                                              |
+----+-------------+------------+--------+---------------+---------+---------+-------+--------+----------------------------------------------------+
|  1 | PRIMARY     | <derived2> | ALL    | NULL          | NULL    | NULL    | NULL  |     15 | Using temporary; Using filesort                    |
|  1 | PRIMARY     | u          | eq_ref | PRIMARY       | PRIMARY | 4       | o.uid |      1 | NULL                                               |
|  1 | PRIMARY     | p          | ALL    | PRIMARY       | NULL    | NULL    | NULL  |      6 | Using where; Using join buffer (Block Nested Loop) |
|  2 | DERIVED     | o          | index  | NULL          | idx_1   | 5       | NULL  | 909112 | Using where                                        |
+----+-------------+------------+--------+---------------+---------+---------+-------+--------+----------------------------------------------------+複製代碼

 

8、中間結果集下推

再來看下麵這個已經初步優化過的例子(左連接中的主表優先作用查詢條件):

 

 

 

SELECT    a.*, 
          c.allocated 
FROM      ( 
              SELECT   resourceid 
              FROM     my_distribute d 
                   WHERE    isdelete = 0 
                   AND      cusmanagercode = '1234567' 
                   ORDER BY salecode limit 20) a 
LEFT JOIN 
          ( 
              SELECT   resourcesid, sum(ifnull(allocation, 0) * 12345) allocated 
              FROM     my_resources 
                   GROUP BY resourcesid) c 
ON        a.resourceid = c.resourcesid複製代碼

 

那麼該語句還存在其它問題嗎?不難看出子查詢 c 是全表聚合查詢,在表數量特別大的情況下會導致整個語句的性能下降。

其實對於子查詢 c,左連接最後結果集只關心能和主表 resourceid 能匹配的數據。因此我們可以重寫語句如下,執行時間從原來的2秒下降到2毫秒。

 

 

 

SELECT    a.*, 
          c.allocated 
FROM      ( 
                   SELECT   resourceid 
                   FROM     my_distribute d 
                   WHERE    isdelete = 0 
                   AND      cusmanagercode = '1234567' 
                   ORDER BY salecode limit 20) a 
LEFT JOIN 
          ( 
                   SELECT   resourcesid, sum(ifnull(allocation, 0) * 12345) allocated 
                   FROM     my_resources r, 
                            ( 
                                     SELECT   resourceid 
                                     FROM     my_distribute d 
                                     WHERE    isdelete = 0 
                                     AND      cusmanagercode = '1234567' 
                                     ORDER BY salecode limit 20) a 
                   WHERE    r.resourcesid = a.resourcesid 
                   GROUP BY resourcesid) c 
ON        a.resourceid = c.resourcesid複製代碼

 

但是子查詢 a 在我們的SQL語句中出現了多次。這種寫法不僅存在額外的開銷,還使得整個語句顯的繁雜。使用 WITH 語句再次重寫:

 

 

 

WITH a AS 
( 
         SELECT   resourceid 
         FROM     my_distribute d 
         WHERE    isdelete = 0 
         AND      cusmanagercode = '1234567' 
         ORDER BY salecode limit 20)
SELECT    a.*, 
          c.allocated 
FROM      a 
LEFT JOIN 
          ( 
                   SELECT   resourcesid, sum(ifnull(allocation, 0) * 12345) allocated 
                   FROM     my_resources r, 
                            a 
                   WHERE    r.resourcesid = a.resourcesid 
                   GROUP BY resourcesid) c 
ON        a.resourceid = c.resourcesid複製代碼

 

總結

資料庫編譯器產生執行計劃,決定著SQL的實際執行方式。但是編譯器只是儘力服務,所有資料庫的編譯器都不是盡善盡美的。

上述提到的多數場景,在其它資料庫中也存在性能問題。瞭解資料庫編譯器的特性,才能避規其短處,寫出高性能的SQL語句。

程式員在設計數據模型以及編寫SQL語句時,要把演算法的思想或意識帶進來。

編寫複雜SQL語句要養成使用 WITH 語句的習慣。簡潔且思路清晰的SQL語句也能減小資料庫的負擔 。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 許可權的基本介紹: rwx許可權詳解: rwx作用到文件: [r]:代表可讀,可以讀取、查看 [w]:代表可寫,可以修改,但不代表可以刪除該文件,刪除一個文件的前提條件是對該文件所在的目錄有寫許可權才能刪除該文件 [x]:代表可執行 rwx作用在目錄: [r]:代表可讀,可以讀取、ls查看目錄內容 [w] ...
  • 平常我經常使用 htop 工具來進行對主機進行性能檢測。但是它只能對 進行進行管理。並簡要顯示 進程和cpu和記憶體使用信息; glances 是比較好的性能檢測工具。相比較htop還能顯示 disk io net 等更多信息。並且還有web ui和ipc 模式。當我們有多台機器的時候,使用此工具極為 ...
  • 使用 Linux 好久了,一定會意識到一個問題,某個分區容量不夠用了,想要擴容怎麼辦?這裡就涉及到 LVM 邏輯捲的管理了,可以動態調整 Linux 分區容量。 ...
  • [20190823]關於CPU成本計算2.txt--//前幾天探究CPU cost時遇到的問題,獲取行成本時我的測試查詢結果出現跳躍,不知道為什麼,感覺有點奇怪,分析看看。--//ITPUB原始鏈接已經不存在,我的日記本還有記錄,現在想想當時的記錄思路很亂,不過這些都是猜測的過程,以前思路混亂也是正 ...
  • 前言: 前面幾篇文章為大家介紹了各種SQL語法的使用,本篇文章將主要介紹MySQL用戶及許可權相關知識,如果你不是DBA的話可能平時用的不多,但是瞭解下也是好處多多。 1.創建用戶 官方推薦創建語法為: 通常我們常用的創建語法為: 語法說明如下: 1) 指定創建用戶賬號,格式為 'user_name' ...
  • /*the waiting game:儘管人生如此艱難,不要放棄;不要妥協;不要失去希望*/ 隨著MySQL MGR的版本的升級以及技術成熟,在把MHA拉下神壇之後, MGR越來越成為MySQL高可用的首選方案。MGR的搭建並不算很複雜,但是有一系列手工操作步驟,為了簡便MGR的搭建和故障診斷,這裡 ...
  • datanode無法連接到namenode namenode在清空hadoop.tmp.dir和namenode.dir文件夾重新格式化後,datanode還是無法連接到namenode並報錯: hdfs.server.datanode.DataNode: Problem connecting to ...
  • 一、集群規劃 這裡搭建一個 3 節點的 HBase 集群,其中三台主機上均為 。同時為了保證高可用,除了在 hadoop001 上部署主 服務外,還在 hadoop002 上部署備用的 服務。Master 服務由 Zookeeper 集群進行協調管理,如果主 不可用,則備用 會成為新的主 。 二、前 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...