R语言实战第一,二章SQL版
這是之前使用R語言完成的一道簡單的數據統計題目鏈接:
https://zhuanlan.zhihu.com/p/27092971
完成之后心理還是有點小得意的。但和答案一對比就發現問題了,自己的計算數據和正確結果差距太大了。看來我用語言暫時還是很難保證數據計算的準確性, 所以有了這篇,畢竟SQL語句更熟悉一些。
環境準備
要使用SQL查詢自然要先有數據庫了,有了docker技術后,我就不太傾向于直接在電腦上安裝軟件了,所以這次要先將MySQL在docker中啟動起來。我使用的是Mac,docker的安裝就不贅述了,直接總官網下載就可以了,目前Mac已經不在使用boot2docker了,號稱是原生docker,但經過這次實踐發現,其實談不上原生,依舊是虛擬機方式實現的,只不過不再使用VirtualBox了,關于這點會在后面進行解釋。接下來開始操作。
先下載mysql的docker image
docker pull mysql:5.6啟動mysql
docker run --name mysql -e MYSQL_ROOT_PASSWORD=mysql -d mysql:5.6 -p 3306:3306 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci這時問題就出現了, 以守護進程形式啟動mysql時, 總是自動退出, 而且按照docker提供的日志存儲目錄(/var/lib/docker)根本就找不到, 系統上就沒有這個目錄. 沒有日志又沒法定位問題, 真是沒想到第一步就卡住了.
只好到網上搜索為什么Mac系統上沒有docker的日志目錄,找到了一些線索:Mac依舊使用虛擬機實現的docker,所有的文件都保存在一個虛擬機的鏡像文件里,"/var/lib/docker"其實是虛擬機中的目錄,所以在Mac上當然找不到。但是也有辦法進入虛擬機內部查看目錄結構:
screen ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/tty接下來就比較分析問題了,mysql沒能啟動的主要原因還是docker run命令的參數順序問題, 調整一下就好了。
docker run -d --name mysql -p 3306:3306 -v /Users/blackpiglet/Documents/big_data:/mnt/big_data -e MYSQL_ROOT_PASSWORD=mysql -e MYSQL_DATABASE=big_data mysql:5.6導入數據
MySQL終于啟動成功了,接下來就要倒入csv文件,在倒入之前要先把表建好:
create table `users` (`user.id` varchar(100), `signup.date` DATE); create table `purchases` (`user.id` varchar(100), `purchase.date` DATE, `purchase.count` smallint); create table `messages` (`user.id` varchar(100), `message.date` DATE, `message.count` smallint);倒入csv文件的語句:
LOAD DATA LOCAL INFILE '/mnt/big_data/users.csv'INTO TABLE `users`FIELDS TERMINATED BY ',' ENCLOSED BY '"'LINES TERMINATED BY '\n'IGNORE 1 LINES(`user.id`, `signup.date`);LOAD DATA LOCAL INFILE '/mnt/big_data/purchases.csv'INTO TABLE `purchases`FIELDS TERMINATED BY ',' ENCLOSED BY '"'LINES TERMINATED BY '\n'IGNORE 1 LINES(`user.id`, `purchase.date`, `purchase.count`);LOAD DATA LOCAL INFILE '/mnt/big_data/messages.csv'INTO TABLE `messages`FIELDS TERMINATED BY ',' ENCLOSED BY '"'LINES TERMINATED BY '\n'IGNORE 1 LINES(`user.id`, `message.date`, `message.count`);查詢注冊90天內購買的用戶數量
查詢注冊用戶數量, 并刪除注冊日期為'0000-00-00'的項.
select count(*) from users where `signup.date` != '0000-00-00'; 23841SET SQL_SAFE_UPDATES = 0; delete from `users` where `signup.date` = '0000-00-00';查詢注冊90天內購買的用戶數量。
這里需要注意一點MySQL的日期計算最好不要直接使用算數運算,在這個語句前使用的是
and (p.purchase.date - u.signup.date) <= 90
結果計算的數量就比實際的數量少了很多,目前還不確定造成這個現象的原因,總之盡量是用date的計算函數。
在進行用戶表,購買表和短信消息表的聯合查詢時,查詢時長超過了30s,MySQL報錯:
Error Code: 2013. Lost connection to MySQL server during query我使用的是MySQL WorkBench,發現可以通過設置修改查詢的超時時長,按照下面這個答案修改超時時長為3000s:
https://stackoverflow.com/questions/2698401/how-to-store-mysql-query-results-in-another-table
修改后依舊查詢超慢,可能是因為查詢缺少優化,而且同時查詢三張表,導致速度緩慢,優化的方法,可以將上一步用戶表和購買表的聯合查詢結果先保存到一個中間表,然后將查詢條件建好索引,之后再嘗試。但是這次使用讓我感覺是R確實在速度上比MySQL要快一些。
以下是使用三表聯合查詢的語句,真是慢的要死,幾十分鐘都沒有響應。后來實在是沒有辦法,只能查詢正在進行的query,然后kill了。
select count( distinct (u.`user.id`)), u.`signup.date`, p.`purchase.date`, p.`purchase.count` from users ujoin purchases p on p.`user.id` = u.`user.id`join messages m on m.`user.id` = u.`user.id`where (p.`purchase.date` - u.`signup.date`) >= 1and (p.`purchase.date` <= date_add(u.`signup.date`, INTERVAL 90 DAY))and (m.`message.date` >= date_add(u.`signup.date`, INTERVAL 1 DAY))and (m.`message.date` < p.`purchase.date`);以下是創建新表,和將數據倒入新表,并創建索引的過程。
create table `user_purchase` (`user.id` varchar(100), `signup.dae` DATE, `purchase.date` DATE, `purchase.count` smallint);insert into user_purchase select distinct(u.`user.id`), u.`signup.date`, p.`purchase.date`, p.`purchase.count` from users ujoin purchases p on p.`user.id` = u.`user.id`where (p.`purchase.date` - u.`signup.date`) >= 1and (p.`purchase.date` <= date_add(u.`signup.date`, INTERVAL 90 DAY));alter table user_purchase add index `index_user_id` (`user.id`); alter table user_purchase add index `index_signup_date` (`signup.date`); alter table user_purchase add index `index_purchase_date` (`purchase.date`);# 給messages表也要創建好索引: alter table messages add index `index_user_id` (`user.id`); alter table messages add index `index_message_date` (`message.date`);查詢90天內未購用戶和收到短信的比例
創建一張新表,用于保存注冊90天內未購買的用戶信息。將users表中有,而user_purchase(保存注冊90天內購買的用戶信息)中沒有的行插入user_not_buy表。
create table user_not_buy (`user.id` varchar(100), `signup.date` DATE);insert into user_not_buy select * from users where users.`user.id` not in (select `user.id` from user_purchase );給新表加上索引
select count(*) from user_not_buy; alter table user_not_buy add index `index_user_id` (`user.id`); alter table user_not_buy add index `index_signup_date` (`signup.date`);查詢收到的短信日期大于注冊日期,并且小于注冊日期90天的記錄。
select count( distinct(u_n_b.`user.id`) ) from user_not_buy as u_n_bjoin messages m on u_n_b.`user.id` = m.`user.id`and (m.`message.date` >= date_add(u_n_b.`signup.date`, INTERVAL 1 DAY))and (m.`message.date` <= date_add(u_n_b.`signup.date`, INTERVAL 90 DAY));# count( distinct(u_n_b.`user.id`) ) '16363' 《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的R语言实战第一,二章SQL版的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CxImage的使用及基本用法
- 下一篇: linux 系统优化,调优