程式設計師程式碼的編寫能力主要體現在思維的嚴謹上。有些看起來很簡單的東西,裡面包含很多很細的點,你能想到嗎?今天我就簡單說一下一個例子,讓大家學習到新知識的同時,也養成一種思維的習慣。
有一張收藏表,裡面儲存的是使用者和圖書ID。資料量為1億。現在要求分頁獲取所有使用者ID(不重複),寫下你的sql語句。
表結構大致如下:
1 2 3 4 5 6 7 8 |
CREATE TABLE 收藏表( `id` bigint(20) unsigned NOT NULL auto_increment COMMENT 'primary key', `uid` bigint(20) unsigned NOT NULL default 0 COMMENT 'uid',<br> `status` tinyint(3) unsigned NOT NULL default 0 COMMENT 'status', `book_id` bigint(20) unsigned NOT NULL default 0 COMMENT 'book Id', `create_time` int(11) unsigned not null default 0 COMMENT 'create time', PRIMARY KEY (`id`), UNIQUE KEY `uid_book_id` (`uid`, `book_id`),<br> KEY `uid_status` (`uid`, `status`) )ENGINED=Innodb Auto_increment=1 default charset=gbk COMMENT '使用者收藏資訊'; |
三種設計
最容易想到的第一種分頁語句是(這也是我們最容易想到的語句):
1 2 |
select distinct uid from 收藏表 order by uid desc limit 0, 10; select distinct uid from 收藏表 order by uid desc limit 11, 10; |
再高階點語句,第二種($last_min_uid表示上一次讀到的最後一個uid):
1 2 |
select distinct uid from 收藏表 order by uid desc limit 10; select distinct uid from 收藏表 where uid < $last_min_uid order by uid desc limit 10; |
最高階的方式
1 2 |
select uid from 收藏表 group by uid order by uid desc limit 10; select uid from 收藏表 group by uid having uid < $last_min_uid order by uid desc limit 10; |
分析
以上三種方式都可以實現分頁獲取到使用者ID列表,那麼區別是什麼?我現在就把每一種跟大家分析下。
第一種在業務場景中,會出現丟資料的情況。——這是比較嚴重的情況,不予採納。
具體的業務場景是這樣的:當你讀取第5頁的時候,前四頁的使用者id列表中,假如有一頁的使用者ID從庫中刪除掉,那麼你這時讀到的第5頁(limit 51, 10),就是原來的第6頁,你會把1頁的使用者ID丟失掉。
第二種的第二條語句,通過explain分析,實際並沒有命中唯一索引,而只是命中了一般索引,資料查詢範圍在7百萬級別,故explain建議我們使用group by。——這個查詢會有嚴重的效能問題。
1 2 3 4 5 |
+----+--------------+---------------+-------+------------------- | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+--------------+---------------+-------+------------------- | 1 | SIMPLE | ubook_room | range | uid_book_id | uid_status | 4 | NULL | 7066423 | Using where; Using index for group-by; Using temporary; Using filesort | +----+--------------+---------------+-------+------------------- |
第三種explain分析,資料查詢範圍在12萬級別(跟第二種相差一個數量級),查詢效能高。
1 2 3 4 5 |
+----+--------------+---------------+-------+------------------- | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+---------------+------------+-------+-----------------+-----------------+---------+--- | 1 | SIMPLE | 收藏表 | index | NULL | uid_book_id | 12 | NULL | 121719 | Using index | +----+---------------+------------+-------+-----------------+-----------------+---------+--- |