如何提高mysql中頻繁更新表的性能?
我的表結構::
CREATE TABLE `gps_device_data`( `imei_no` bigint(15) NOT NULL DEFAULT '0', `ioelementpriority` int(1) DEFAULT NULL, `longitude` int(15) DEFAULT NULL, `latitude` int(15) DEFAULT NULL, `speed` tinyint(3) unsigned DEFAULT NULL, `iovalue` varchar(254) DEFAULT NULL, `odom` bigint(20) DEFAULT NULL, `alarm_category_realtime_id` varchar(70) DEFAULT NULL, `angle` int(4) DEFAULT NULL, `altitude` int(4) DEFAULT NULL, `satellites` int(4) DEFAULT NULL, `data_received_time` bigint(20) NOT NULL DEFAULT '0', `continue_data_received_time` bigint(20) NOT NULL DEFAULT '0', `movement` int(2) DEFAULT NULL, `eventsource` int(4) DEFAULT NULL, `data_location` varchar(250) DEFAULT NULL, `data_poi` varchar(100) DEFAULT NULL, `data_validity` enum('valid','invalid') DEFAULT NULL, `createdby` varchar(10) DEFAULT NULL, `createddate` datetime DEFAULT NULL, `modifiedby` varchar(10) DEFAULT NULL, `modifieddate` datetime DEFAULT NULL, `deletedby` varchar(10) DEFAULT NULL, `deleteddate` datetime DEFAULT NULL, PRIMARY KEY (`imei_no`,`data_received_time`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1
為車輛生成報告需要花費太多時間的查詢。
select odom,latitude/10000000 as latitude,longitude/10000000 as longitude, imei_no,iovalue,data_received_time,continue_data_received_time, data_location from gps_device_data where imei_no IN (7781112889,70433357641,356173061134123, 865190010626029,354188046466178,356307040285917,863354010100132, 863354010100107,8511139808,4209501721,9974052815,356307044188414, 5252563256,7709111078,7043335764,2121212121,7043333691, 7043333684,7043338378,100345,356307048930860,356307040328584, 358899052926188,7621013796,7043132917,7043312765,9016102493, ... 7820046194,8585858585,559862234897,123456789001,78000000021, 2220002220,12345678911,863771023760608,863771023758834, 9898787854,140507978,140908877,140507779,356173061103755, 7485961230,454545454,147852390,1203203695,358174067325903 ) and data_received_time >= 1430463600000 and data_received_time <= 1446274800000 Order by imei_no,data_received_time;
我的解釋計劃
+----+-------------+-----------------+-------+---------------+---------+---------+------+--------+-------------+ | 編號 | 選擇類型 | 表| 類型 | 可能的鍵 | 關鍵 | key_len | 參考 | 行 | 額外 | +----+-------------+-----------------+-------+---------------+---------+---------+------+--------+-------------+ | 1 | 簡單 | gps_device_data | 範圍 | 初級 | 初級 | 16 | 空 | 629357 | 使用位置 | +----+-------------+-----------------+-------+---------------+---------+---------+------+--------+-------------+
我的項目所做的是跟踪車輛獲取其資訊並將該資訊顯示給特定的車主。
問題:
是否有任何替代查詢可以為我提供比上述指定查詢更高的性能?
可以在 IN 塊中使用複合鍵嗎?
我的選擇查詢需要 25.93 秒才能執行。如果我上面的選擇查詢需要 2 或 3 秒來執行它的好表單。如何減少選擇查詢的時間?
我在 gps_device_data 表中有 1000 萬行。
您有兩個“範圍”過濾數據。MySQL 沒有很好的方法來做到這一點。
首先,讓我們檢查一些數字。
- 結果集中有多少行?
- 有多少行沒有 IN 子句?
- 有多少行沒有時間範圍?
- 這個 IN 列表和這個時間範圍是典型的嗎?
有了這些,我們也許可以決定專注於過濾優先於 IN 範圍的時間範圍。
同時,讓我們擺脫“午夜”錯誤……您的時間範圍似乎是從 5 月 1 日早上到 10 月 31 日早上的午夜。也許您的意思是包括 10 月 31 日的所有時間,而不僅僅是一毫秒那天?你的意思是要整整6個月嗎?建議這種編碼風格;它不太容易出錯:
AND data_received_time >= 1000 * UNIX_TIMESTAMP('2015-05-01') AND data_received_time < 1000 * (UNIX_TIMESTAMP('2015-05-01') + INTERVAL 6 MONTH)
回到性能問題…
如果您正在查看總時間的一小部分,那麼
PARTITIONing
可能對模擬 2D 索引很有用。(我在http://mysql.rjweb.org/doc.php/partitionmaint中將其作為案例 #2 提到)如果您將表分成 20-40 個分區
PARTITION BY RANGE(data_received_time)
,那麼“分區修剪”將首先過濾時間範圍。然後你的PRIMARY KEY
,imei_no
首先,過濾另一個維度。我不能說這種分區會加快多少(如果有的話)。我希望小時間範圍(按百分比)受益最多。命中所有分區的時間範圍實際上會比沒有分區慢一點。(因此,我的“檢查一些數字”問題。)
架構註釋…(越小越快)
BIGINT
是 8 個字節。可以odom
超過 16M 英里,對於 `MEDIUMINT UNSIGNED (3 bytes) 的限制?INT(4)
——(n)
毫無意義;建議TINYINT
(1 字節)或SMALLINT
(2 字節)。- 其中一些
VARCHARs
可以“規範化”為 2-byteSMALLINT UNSIGNED
。
建議您僅在測試環境中測試一些東西,在這裡它們是..
創建非聚集索引(SQL Server 語法,請轉換為 MySQL)。
CREATE NONCLUSTERED INDEX IX_Data_Received_Time ON [gps_device_data] ( data_received_time) INCLUDE (latitude,longitude, iovalue ,odom , continue_data_received_time ,data_location)
執行以下查詢(沒有 ORDER BY 子句)並重新排列列。
SELECT imei_no , latitude / 10000000 AS latitude , longitude / 10000000 AS longitude , iovalue , odom , data_received_time , continue_data_received_time , data_location FROM gps_device_data WHERE imei_no IN (7781112889 ,70433357641 ,356173061134123 , 865190010626029 ,354188046466178 ,356307040285917 ,863354010100132 , 863354010100107 ,8511139808 ,4209501721 ,9974052815 ,356307044188414 , 5252563256 ,7709111078 ,7043335764 ,2121212121 ,7043333691 ,7043333684 , 7043338378 ,100345 ,356307048930860 ,356307040328584 ,358899052926188 , 7621013796 ,7043132917 ,7043312765 ,9016102493 ,99684 ,356173060920357 , 4455663388 ,4561234563 ,352134012038180 ,9998757966 ,356173060928988 , 103958456 ,356173061023987 ,356173060672560 ,7028015271 ,115599335577658 , 7694003740 ,595 ,9999999 ,356173061489196 ,863354010100189 ,4521452145 , 863354010100109 ,356917050308381 ,356173060952137 ,356917050324768 , 9096627854 ,88048286707 ,111111111211412 ,125 ,126 ,127 ,128 ,129 ,130 , 131 ,132 ,133 ,134 ,112254213688 ,11225421 ,112254213690 ,112254213691 , 112254213692 ,112254213693 ,112254213694 ,112254213695 ,112254213696 , 112254213697 ,112254213698 ,112254213699 ,112254213700 ,112254213701 , 112254213702 ,112254213703 ,112254213704 ,112254213705 ,112254213706 , 112254213707 ,112254213708 ,112254213709 ,12345678 ,1346243 ,3474698 , 34276592 ,763875 ,356173060917866 ,32 ,982317 ,45368437 ,643876324 , 128749874 ,2346538725 ,374984 ,214385896 ,7493682798 ,3986967 ,82365897 , 967564 ,49703698 ,21979779 ,356173061111345 ,4434 ,54 ,214124 ,466644 , 352134012038189 ,43432434 ,434344 ,344434 ,6666666 ,888888 ,4980948 , 540000 ,455436 ,9055609 ,89909 ,5555254 ,1112 ,353173064190752 ,219105 , 878758584876987 ,8796541258 ,258964758232541 ,9510222625 ,8523014711 , 8523014798 ,785412365478965 ,356173060806358 ,7820046194 ,8585858585 , 559862234897 ,123456789001 ,78000000021 ,2220002220 ,12345678911 , 863771023760608 ,863771023758834 ,9898787854 ,140507978 ,140908877 , 140507779 ,356173061103755 ,7485961230 ,454545454 ,147852390 ,1203203695 , 358174067325903) AND data_received_time >= 1430463600000 AND data_received_time <= 1446274800000;
請告訴我這個修改後的查詢返回結果所花費的時間?