發表文章

目前顯示的是有「MYSQL」標籤的文章

[PHP][MYSQL] PHP+MySQL 批量更新百萬級資料的最佳策略

在處理數十萬甚至數百萬筆資料的更新任務時,許多開發者習慣使用迴圈執行單條 UPDATE 語句。但當資料量過大時,這種做法會導致應用程式卡死、資料庫負載飆升,效率極低。 本文將介紹一種資料庫專業人士常用的高效解決方案: 使用 UPDATE JOIN 搭配臨時表(Temporary Table) 。 🎯 什麼是批量更新的「效能殺手」? 當您使用 PHP 迴圈執行 10 萬次 UPDATE ... WHERE id = X 時,主要的效能瓶頸並不是資料庫處理本身,而是: 網絡傳輸延遲: 10 萬次 PHP 應用伺服器與 MySQL 伺服器之間的通訊。 SQL 解析開銷: MySQL 必須解析、驗證和優化 10 萬次 SQL 語句。 磁碟 I/O 寫入: 缺乏事務(Transaction)保護下,每一次更新都可能觸發一次昂貴的磁碟日誌寫入。 我們的目標是將這 10 萬次操作,轉換為 一次高效、單一的資料庫操作 。 💡 最佳策略:UPDATE JOIN + 臨時表 這個策略的核心思路是: 收集新值: 將所有需要更新的新資料(例如 uid 和 name )組裝起來。 快速載入: 將這些新值一次性快速載入到一個輕量級的 臨時表 中。 單次執行: 執行一個高效的 UPDATE JOIN 語句,讓資料庫在內部利用索引完成所有幾十萬筆資料的更新。 適用情境 異質更新: 每筆資料要更新的目標值都不同(例如:客戶 A 積分變 100,客戶 B 積分變 200)。 非唯一鍵更新: 主表中的關聯鍵(如您的 uid )可能 重複 。 🛠️ 實戰教學:三步驟完成百萬級更新 假設我們有一個名為 performance_records 的業績表, uid 欄位會重複,我們需要根據新的清單來更新所有匹配的 name 欄位。 步驟 1:建立並填充臨時表 (使用 PHP 批量 INSERT) 我們首先建立一個臨時表 temp_name_updates ,並將幾十萬筆新資料高效地寫入。 關鍵優化: 在臨時表上建立 主鍵 ( PRIMARY KEY ) ,這能極大地加速稍後的 JOIN 關聯速度。 // 假設 $pdo...

[MYSQL] 使用 SQL 語法 快速建立使用者帳號

使用 phpMyAdmin 的圖形介面(GUI)來設定 MySQL 使用者權限雖然直觀,但在建立大量帳號或需要精確、批次管理權限時,直接使用 SQL 語法 會是更快、更安全、更有效率的方法。 其實只要三行簡單的 SQL 語法,就能從零開始建立一個新帳號,並賦予所需的權限。 三行語法快速建立新使用者 我們將以建立一個名為 report_user 的帳號為例,目標是只讓它能讀取 product_db 資料庫中的 sales_data 資料表。 1:建立使用者並設定密碼 這是建立使用者帳號並設定初始密碼的第一步。請務必使用一個強密碼。 -- CREATE USER '使用者名稱'@'連線來源' IDENTIFIED BY '密碼'; CREATE USER 'report_user'@'%' IDENTIFIED BY 'StrongP@ssw0rd!'; 參數 說明 'report_user' 您要創建的使用者名稱。 '%' 連線來源。 % 代表允許從 任何 IP 位址 連線。如果只允許從本機連線,請改用 'localhost'。 'StrongP@ssw0rd!' 設定該帳號的登入密碼。 💡 注意: 執行此指令後,該使用者已經具備最基礎的連線能力 (USAGE 權限),有些教學文章會在建立帳號後,接一個給予連線能力的SQL語法,其實可以省略。 2:授予操作權限 這是關鍵步驟。我們只授予使用者 讀取 (SELECT)特定資料表的權限,確保它不能新增、修改或刪除任何資料。 -- GRANT 權限列表 ON `資料庫名稱`.`資料表名稱` TO '使用者名稱'@...

[MYSQL][PHP] 如何不影響使用者操作 完成大資料表的更新

有些資料表需要每日更新,而更新過程需要一段時間,一般的作法是刪掉舊資料,然後寫入新資料,過程中使用者可能會因為舊資料被刪掉又還沒寫入新資料,導致系統產生錯誤。 為了避免發生這種情形,較好的更新資料策略為:

[MYSQL] 最簡單的單筆(或多筆)資料備份語法 (同table或不同table皆可)

單筆: 表A的某筆資料(例如:id=5) 要變動前,希望能先備份到表B,語法如下: INSERT INTO table_b SELECT * FROM table_a WHERE table_a.id = '5' 多筆: 表A的多筆資料(例如:type=1) 要變動前,希望能先備份到表B,語法如下: INSERT INTO table_b SELECT * FROM table_a WHERE table_a.type = '1' 此時table_a只要type是1的資料,不管幾筆都會寫到table_b。 部分欄位修改: 假設我要要將表A中type=1的資料,全部複製一份,且同時改寫部分欄位,語法如下: INSERT INTO table_a (`type`, `name`, `qty`) SELECT 2, `name`, NULL FROM table_a WHERE table_a.type = '1' 此時table_a只要是type是1的資料,會全部複製一份,且type改為2、name維持一樣、qty全部為NULL,新增到資料表上。

[MAC][MYSQL] 如何在MAC上安裝MYSQL (以 MYSQL5.7 為例)

1. 至 MYSQL 官網 下載.dmg 安裝檔 2. 執行安裝程序 最後系統會給一個隨機密碼 先記下來 3. 加環境變數 $export PATH=${PATH}:/usr/local/mysql/bin/ $source ~/.bash_profile 4. 改root密碼 $mysql -h localhost -u root -p 輸入隨機密碼 進入mysql文字操作介面 SET PASSWORD FOR 'root'@'localhost' = PASSWORD('mypassword'); 5. 完成後,就可以用root跟新密碼來登入 phpmyadmin 或 其他DB工具(如:sequel pro)了。

[MYSQL] 建立索引(INDEX)的語法

第一種: CREATE INDEX my_index ON my_table(col_a); 第二種: ALTER TABLE my_table ADD INDEX(col_a); 效果是一樣的,差別在第一種需要幫索引命名,第二種會自動命名。 備註: 建立一個複合索引的語法 ALTER TABLE my_table ADD INDEX(col_a, col_b); 一次建立多個單一索引的語法 ALTER TABLE my_table ADD INDEX(col_a), ADD INDEX(col_b);

[MYSQL] SQL查詢卡住時 如何處理 (使用 show processlist;)

使用下列SQL語法可查出目前卡住的查詢,然後在 phpmyadmin 可以直接 kill show full processlist;

[MYSQL] 如何在 select 時,使用類似 PHP 的 switch 功能

官網介紹   範例1.  SELECT  CASE 1  WHEN 1 THEN 'one' WHEN 2 THEN 'two'  ELSE 'more'  END 範例2.  SELECT  CASE cid  WHEN 'kr' THEN 'Korea' WHEN 'jp' THEN 'Japan'  ELSE 'Taiwan'  END AS country FROM customer 說明:假設客戶資料表只有國家簡碼(cid, eg. jp...),但需求 select 出來時要顯示國家全名。

[PHP][MYSQL] 如何知道SQL連線是否已關閉?(使用 ping() ,以 mysqli 為例)

當程式碼非常複雜時,有時我沒無法確定當下是否仍與SQL保持連線,這時可以透過 ping() 這個方法去測試,使用方法很簡單...

[MYSQL] 找出特定日期的前或後幾周(月、季...等)的日期 (使用 DATE_ADD )

MySQL 真是太貼心了 直接看W3官網介紹 這裡

[PHP][MYSQL] 使用 PDO 在 INSERT 或 UPDATE 時,如何在沒有值時寫入 NULL?

有值就寫值,沒值就寫NULL $sth->execute(array(     'tel' => ($tel?$tel:null) ));

[MYSQL] 如何在 WHERE 中用類似 switch, if 的條件判斷式 (使用 CASE WHEN THEN ELSE END)

假設我們的資料表如下 name class score Allen B 78 Bill A 85 Cindy A 77 Dennis B 74 Ellen C 81 如果我們需要把A班考80分以上、B班考75分以上的學生找出來,只要使用下列語法,就可以簡單達成囉...

[MYSQL][SQLite] MYSQL 的預設時間區是 local timezone 跟 SQLite 則是 GMT

有時候我們會直接用SQL抓當下時間,例如 MYSQL: SELECT NOW();  //顯示2016-12-01 10:00:00 SQLite: SELECT datetime();  //顯示2016-12-01 02:00:00 可以發現兩個相差了八小時,那是因為 SQLite 抓的是 GMT 時間,MYSQL 抓的是 localtime (Asia/Taipei)。 如果要讓 SQLite 抓到 localtime,請使用下面的語法 SELECT datetime('now', 'localtime');  //顯示2016-12-01 10:00:00

[MYSQL] VARCHAT 型態的欄位值 比大小結果不正確的快速解法

假設有兩個欄位 A & B 型態為 VARCHAT,A欄位存 '10'、B欄位存 '3',語法如下: SELECT IF(A > B, 1, 0) AS ans FROM mytable 直覺反應 ans 會是 1,但是結果會是 0。 快速解法如下: SELECT IF((A + 0) > (B + 0), 1, 0) AS ans FROM mytable 透過+0這個動作讓型態轉成數值。

[MYSQL] 查出資料表的基本資料

SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'my_db' AND TABLE_NAME = 'my_table'  可以查出很多資訊,如:資料表的建立時間、使用何種ENGINE...等 ( MySQL官網 ) TABLE_CATALOG TABLE_SCHEMA TABLE_NAME TABLE_TYPE ENGINE VERSION ROW_FORMAT TABLE_ROWS AVG_ROW_LENGTH DATA_LENGTH MAX_DATA_LENGTH INDEX_LENGTH DATA_FREE AUTO_INCREMENT CREATE_TIME UPDATE_TIME CHECK_TIME TABLE_COLLATION CHECKSUM CREATE_OPTIONS TABLE_COMMENT

[SQLite][MYSQL][PHP] 如何在迴圈 快速新增多筆資料 (fast multi insert) (使用Transaction交易模式,多筆query一次commit)

SQLite 有支援一次多筆insert的語法,但時候我們受限於PHP程式而必需在迴圈中一筆一筆的執行 SQL 的 insert,少量資料這樣做是OK的,但當資料筆數過多(例如超過一萬筆),就必需使用一個小技巧,方法很簡單...

[MAC][PHP][Laravel][MYSQL] 如何查看 Homestead 的資料庫 (以 MYSQL 為例,使用 Sequel Pro)

假設 Homestead 已經安裝好,首頁可以正常顯示了。 Step 1. 先安裝一套在MAC環境下免費好用的 MySQL GUI  【 Sequel Pro 】。 Step 2. 啟動後,輸入連線資訊 (預設帳號是 homestead、密碼是 secret、host是192.168.10.10、port是3306)。 (註:Homestead 預設host是 192.168.10.10) Step 3. 左上角 可以選擇要連線的資料庫,這邊選擇 homestead,完成。 註1:如果想要知道 laravel 的DB資訊,可以在專案的根目錄的.env找到。 註2:如果想要改掉homestead這個預設帳號跟密碼,請點選 Sequel Pro 右上角的 "User" 圖示,出現 Accounts 清單後點選 homestead, 然後右邊就可以直接改帳號及密碼,輸入新的帳號跟密碼後,按右下角的Apply,就完成修改了。然後要記得回去改 .env 檔中的 DB_USERNAME 及 DB_PASSWORD。

[MYSQL] 使用 ORDER BY 排序時,讓特定對象排在最上面的方法 (使用 CASE)

uid | joindate A01 | 2015-01-01 A02 | 2016-02-01 A03 | 2016-03-01 我們希望當A02這個User登入時,報表顯示如下 A02 | 2016-02-01 A01 | 2016-01-01 A03 | 2016-03-01 SQL語法如何下呢?...

[MYSQL] INSERT 寫入一筆資料的兩種基本語法

MySQL 官網 基本-語法 1. 單筆: INSERT INTO my_table (col_name1, col_name2,...) VALUES (value1, value2,...) 多筆: INSERT INTO my_table (col_name1, col_name2,...) VALUES (value1, value2,...), (value1, value2,...), ... 基本-語法 2. 單筆: INSERT INTO my_table SET col_name1 = value1, col_name2 = value2,... 進階-語法 3. 複製: INSERT INTO my_table SELECT * FROM other_table WHERE id = '1' 備註: 1. INTO 在 MySQL 3.22.5 之後的版本 可以被省略。 2. 語法2. 在 MySQL 3.22.10 之後的版本 才支援。 3. 語法3. 兩個table欄位必需一致。

[MYSQL][Vim] 如何避免 非中文 (如:日文) 的資料表匯出後,Excel打開會出現亂碼的情形? ( phpmyadmin 匯出) (Notepad++ & Vim)

1. phpmyadmin 匯出時,格式選擇"CSV"。 2. 使用 Notepad++ 開啟 CSV 檔。 3. 編碼 / 轉換至 UTF-8 碼格式。 (目的是為讓CSV檔"加上檔首") 4. 用 Excel 開啟 CSV 檔,搞定。 如果是用Vim編輯器,則可以使用下面三個指令 ( 參考來源 ) 查詢bom :set bomb? 加上bom :set bomb 刪除bom :set nobomb