簡體   English   中英

mysql ORDER BY CASE-太慢,更快的方法嗎?

[英]mysql ORDER BY with CASE - too slow, faster way?

像這樣用CASE看一下ORDER BY各種答案時 ,我發現我不得不在這個遺留應用程序中做的事情很可能是一種專家方法。 但是,當行數少於平凡時(行數超過100,000會導致10秒鍾的頁面加載),速度太慢。

請注意,原始查詢試圖解決一個看似常見的問題,其中查詢分析人員需要的日期與常規的排序方式相比是空的。 在這種情況下, datefirstprinted將降序,但是所有未打印的記錄應填充到列表的頂部。

原來查詢解決了這個,但問題的關鍵是要避免filesort自帶的派生列的性能損失notprintedyet

原始查詢

SELECT SQL_NO_CACHE
  id, daterun, datefirstprinted,
  case datefirstprinted when "0000-00-00 00:00:00" then 1 else 0 end as notprintedyet
FROM
  patientrecords
WHERE
  dateuploaded <> '0000-00-00 00:00:00'
ORDER BY
  notprintedyet desc,                                 /* ordered via alias */
  datefirstprinted desc
LIMIT 10;

時間1.52s


我發現不對別名notprintedyet排序可以節省一些時間:

查詢速度稍快

SELECT SQL_NO_CACHE
  id, daterun, datefirstprinted,
  case datefirstprinted when "0000-00-00 00:00:00" then 1 else 0 end as notprintedyet
FROM
  patientrecords
WHERE
  dateuploaded <> '0000-00-00 00:00:00'
ORDER BY
  datefirstprinted = "0000-00-00 00:00:00" desc,      /* directly ordered */
  datefirstprinted
LIMIT 10;

時間1.37s


最佳速度,但首先缺少必需的空日期排序

SELECT SQL_NO_CACHE
  id, daterun, datefirstprinted,
  case datefirstprinted when "0000-00-00 00:00:00" then 1 else 0 end as notprintedyet
FROM
  patientrecords
WHERE
  dateuploaded <> '0000-00-00 00:00:00'
ORDER BY                        
  datefirstprinted                                     /* not ordered properly */
LIMIT 10;

時間0.48s


我嘗試使用視圖

create view notprinted_patientrecords as (
   SELECT id, daterun, datefirstprinted, case datefirstprinted when "0000-00-00 00:00:00" then 1 else 0 end notprintedyet
   FROM patientrecords
   WHERE dateuploaded <> '0000-00-00 00:00:00'
);

不幸的是,當我跑解釋

 explain select * from notprinted_patientrecords order by notprintedyet desc limit 10;

它表明我仍在使用filesort並花費 1.51s, 也沒有節省


如果datefirstprinted默認為NULL會更快嗎?

也許可以,但是在這個舊版應用中,危害可能比頁面加載時間多出5秒更大


我們還能嘗試什么? 存儲過程? 職能?


更新

如建議的@strawberry-按案例訂購

...
ORDER BY                        
  case datefirstprinted when "0000-00-00 00:00:00" then 1 else 0 end, datefirstprinted
LIMIT 10;

時間1.52s


按照@ e4c5的要求, explain輸出:

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: patientrecords
         type: range
possible_keys: dateuploaded,uploads_report
          key: dateuploaded
      key_len: 5
          ref: NULL
         rows: 299095
        Extra: Using index condition; Using filesort

除非訂購不正確 ,但有以下差異

        rows: 10
        Extra: Using where

創建表語句

*************************** 1. row ***************************
Table: patientrecords
Create Table: CREATE TABLE `patientrecords` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `datecreated` datetime NOT NULL,
  `dateuploaded` datetime NOT NULL,
  `daterun` datetime NOT NULL,
  `datebilled` datetime NOT NULL,
  `datefirstprinted` datetime NOT NULL,
  `datelastprinted` datetime NOT NULL,
  `client` varchar(5) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `dateuploaded` (`dateuploaded`),
  KEY `daterun` (`daterun`),
  KEY `uploads_report` (`dateuploaded`,`client`),
  KEY `datefirstprinted` (`datefirstprinted`),
  KEY `datelastprinted` (`datelastprinted`)
)

查看您的表,首先要注意的是,以下索引是多余的

KEY `dateuploaded` (`dateuploaded`),

這個角色可以充分發揮它的作用

KEY `uploads_report` (`dateuploaded`,`client`),

因此,讓我們刪除dateuploaded鍵。 目前尚不清楚您是否在任何查詢中實際使用了client列。 如果您不這樣做,我相信按照以下方式更改索引將大大提高您的速度

KEY `uploads_report` (`dateuploaded`,`datefirstprinted`,`client`),

這是因為mysql每個表只能使用一個索引。 由於在where子句中使用了dateuploaded列的索引,因此無法使用datefirstprinted的索引。 但是,如果將兩列合並到同一索引中,則可以在sort和where中使用它。

完成上述索引后,可能會刪除該索引:

KEY `datefirstprinted` (`datefirstprinted`),

較少的索引將使您的插入和更新速度更快。

在@ e4c5的幫助下,遵循在級聯索引上學到的想法,我嘗試在兩列上添加鍵(在where列中使用的列,在基於caseorder子句中使用的列):

alter table
  patientrecords
add index
  printedvsuploaded (datefirstprinted, dateuploaded);

由於mysql繼續使用index dateuploaded因此最初沒有效果。

但是,添加force index會減少查詢時間:

SELECT SQL_NO_CACHE
  id, daterun, datefirstprinted
FROM
  patientrecords
FORCE INDEX (printedvsuploaded)
WHERE
  dateuploaded <> '0000-00-00 00:00:00'
ORDER BY
  case when datefirstprinted = "0000-00-00 00:00:00" then 1 else 0 end desc,
  datefirstprinted
LIMIT 10;

時間0.64秒

值得注意的是,我同意@ e4c5的觀點,即額外的索引最終將導致寫入性能下降; 我指望其他路線圖的發展,以幫助減少索引數。 現在,實施此操作會將較大結果集的10秒頁面加載減少到3秒的可管理范圍內,然后將要實施的解決方案。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM