1分組取時間最大的一條:
(1):基於外連接去時間最大然后關聯取最大的頭像,昵稱等
select a.id,a.mobile,b.name,b.head_img,a.salesCount,a.salesPrice,b.recommend_user_id,b.create_time from(SELECT id,REPLACE(mobile,SUBSTR(mobile,4,4), '****') as mobile,NAME,head_img,COUNT(recommend_user_id) AS salesCount , SUM(sales_price) AS salesPrice,recommend_user_id ,max(create_time) as create_time FROM hwxc_activity_guide_bind WHERE activation_status=1 and status=0 GROUP BY recommend_user_id ORDER BY salesCount DESC,salesPrice DESC) a left join hwxc_activity_guide_bind b on a.recommend_user_id=b.recommend_user_id and a.create_time=b.create_time
(2):基於子查詢先排序,然后分組取最大;注意 因為在mysql5.7的時候,子查詢的排序已經變為無效了,可能是因為子查詢大多數是作為一個結果給主查詢使用,所以子查詢不需要排序的原因。
SELECT
id,
REPLACE ( mobile, SUBSTR( mobile, 4, 4 ), '****' ) AS mobile,
NAME,
head_img,
COUNT( recommend_user_id ) AS salesCount,
SUM( sales_price ) AS salesPrice,recommend_user_id
FROM
(select *from hwxc_activity_guide_bind order by create_time desc LIMIT 10000000)
a
WHERE
activation_status = 1
AND STATUS = 0
GROUP BY
recommend_user_id
ORDER BY
salesCount DESC,
salesPrice DESC
對子查詢的排序進行limit限制,此時子查詢就不光是排序,所以此時排序會生效,但是限制條數卻只能盡可能的設置大些
2.分組取每組前三條記錄:
select recommend_user_id ,sales_price from hwxc_activity_guide_bind a where 3>(select count(*) from hwxc_activity_guide_bind b where b.recommend_user_id=a.recommend_user_id and b.sales_price>a.sales_price) order by recommend_user_id desc ,sales_price DESC 結果如下:
注意這不是真正的分組,不能進行聚合統計操作。只是查了排名前三的 注意如果數據一樣你指定1條也會查出多條
加聚合沒有分組會默認只顯示一條數據:
select recommend_user_id ,sales_price , SUM( sales_price ) AS salesPrice from hwxc_activity_guide_bind a where 3>(select count(*) from hwxc_activity_guide_bind b where b.recommend_user_id=a.recommend_user_id and b.sales_price>a.sales_price) order by recommend_user_id desc ,sales_price DESC 結果如下:
3.update selet 批量更新
UPDATE hwxc_activity_guide_bind a INNER JOIN hwxc_user u ON a.user_id=u.id SET a.order_name=CONVERT(u.name USING utf8) COLLATE utf8_unicode_ci,a.order_head_img=u.head_img;
UPDATE hwxc_activity_guide_bind a INNER JOIN (SELECT o.barcode,o.order_no,p.product_name FROM hwxc_order_detail o LEFT JOIN hwxc_product p ON o.barcode=p.barcode ) AS u ON a.order_no=u.order_no SET a.barcode=u.barcode,a.product_name=u.product_name;
UPDATE hwxc_activity_guide_bind b INNER JOIN ( SELECT u.*,p.reward_icon, (p.reward_icon)*(u.sales_count) AS total_reward FROM ( SELECT SUBSTRING_INDEX(o.associated_type_id,'-',-1) AS spell_id,a.barcode AS barcode ,a.sales_count AS sales_count ,a.order_no FROM hwxc_activity_guide_bind a LEFT JOIN hwxc_order o ON a.order_no=o.order_no ) AS u LEFT JOIN app_spell_product p ON u.barcode=p.barcode AND u.spell_id=p.spell_id) t
ON b.order_no=t.order_no SET b.reward_icon=t.total_reward;
注意字符的轉換,當表做外關聯的時候,如果字符串字段編碼集不一樣,需要轉換,字符串不一樣還有可能導致索引失效
4.索引失效:
索引失效
1.字符串類型 隱式轉換成數字索引失效, 若是數字轉字符串則索引不失效
2.字符類型字段字符集不一樣做表關聯查詢的時候,索引也會失效
5.sql語句執行先后順序:
這一條語句包含我們經常用到的一些關鍵字,select,from,where,group by,order by,它的執行順序如下:
先執行from關鍵字后面的語句,明確數據的來源,它是從哪張表取來的。
接着執行where關鍵字后面的語句,對數據進行篩選。
再接着執行group by后面的語句,對數據進行分組分類。
然后執行select后面的語句,也就是對處理好的數據,具體要取哪一部分。
最后執行order by后面的語句,對最終的結果進行排序
記錄一次2千萬條數據遷移過程:
項目背景:公司對現有系統做重構,新系統上線前需要將老系統的全量數據遷移到新的系統,其中有10幾張表的數據有1千多萬的數據量需要全量遷移過來,但是新老系統的表結構不是一樣的,所以我們需要將老系統的數據全部轉化為新系統的數據結構
過程:
項目開始時是從簡單的版本開始做,並沒有考慮速度問題,按照簡單的單線程開發,數據分頁讀取然后做數據轉化后通過mybatis批量寫入數據庫。第一版只是完成業務邏輯上的開發,保證數據不會有誤。完成之后開始第一次測試,
測試過程中發現數據遷移很慢,讀取一次需要幾十秒,批量寫入時每次寫入1000條,批量插入,發現寫入1000條居然要等上半個小時,這個肯定是不行的。於是對寫入做了第一次整改,將寫入由一次寫入1000條改為每次寫入100條,
測試后發現寫入速度快了,由開始的半個小時優化了20-30秒就能完成1000條數據的寫入。接着就開始了多線程的操作,將系統有開始的單個線程讀取轉化寫入過程改成了多線程模式,用一個線程來負責每次從數據庫中讀取1000條,
然后把數據分給多線程去處理這1000天數據的轉化並寫入。第一次嘗試我使用了10個線程,結果測試一跑起來傻眼了,發現數據寫庫由之前的單線程每1000條20-30秒變成100秒以上了,線程越多寫入的性能還越來越慢了。這樣肯定是不行的,
於是經過高手的請教,使用單條插入,批量commit。這里的多線程寫入變慢是因為在批量寫入的時候需要大量的數據庫臨時空間去裝載大sql,並發越多,臨時空間就越不夠用,這也就出現了線程越多,寫入越慢的情況了。經過指點后通過單條提交,
分批commit之后數據寫入性能有了質的飛越,1000條寫入耗時只要7左右秒就能完成,而且多線程也不會影響速度。於是開啟了第二版的飛越,測試一次之后在寫入到了200萬之后速度滿了下來,而且是越來越慢,通過日期觀察寫的數據沒有問題,
那就只有讀的問題了。通過日志分析發現,當數據讀取到了100萬以后,后面的數據讀取越來越慢了,想起了數據庫分頁讀取后面的頁數需要翻過前面一堆數據之后才能讀到,於是我們有隊數據讀取表做了修改,加入了一個自增順序的id,
這樣我們就不用分頁讀取了,每次讀取完以后取最后一個數據id,后面的數據從這個之后讀取就不需要分頁了。每次讀取的速度都是在一個穩定的值。這樣之后我們的性能提升到了只需要幾個小時就能完成了。但是老板對這個速度還不是很滿意,
於是我們引入了多機器,其中一個機器負責讀取id,然后發送到mq中,其他機器從mq中讀取id,根據id來獲取數據並轉化落庫,整個遷移過程就在1小時左右完成了。
總結: 這次全量數據的遷移,學到了2個點,第一點:數據插入並不是批量比單個快,批量sql需要消耗臨時空間,sql越長需要的空間越大。單條插入通過手動控制事物提交到達的性能效果比批量的好;第二點數據讀取分頁到后面會越來越慢,當數據量大的時候,數據查詢和插入結果往往是達不到自己所猜想的,你會有一個驚喜的結果。