都内で働くSEの技術的なひとりごと / Technical soliloquy of System Engineer working in Tokyo

都内でサラリーマンやってます。SQL Server を中心とした (2023年からは Azure も。) マイクロソフト系(たまに、OSS系などマイクロソフト以外の技術も...)の技術的なことについて書いています。日々の仕事の中で、気になったことを技術要素関係なく気まぐれに選んでいるので記事内容は開発言語、インフラ等ばらばらです。なお、当ブログで発信、発言は私個人のものであり、所属する組織、企業、団体等とは何のかかわりもございません。ブログの内容もきちんと検証して使用してください。英語の勉強のため、英語の

ORDER BY について簡単に説明してみる

 最近、すっかりブログを書かなくなりました。習慣化しておかないといけませんね。去年はこんなに書いていたのに...一か月に 10 も投稿していたんだなぁ。
f:id:koogucc11:20170926231920p:plain

 クエリのレビューをしていてふと気が付いたことを書いてみます。それは、ORDER BY。意外と考慮からもれている場合が多く見受けれます。クエリを実行する上で、CPU パワーを使うし、IO も大量に発生させてしまう原因になりやすいです。ORDER BY を効率的に処理させるには、兎に角 Sort オペレータをなるべく出現させないようにする、が鉄則です。早速、AdventureWorks データベースを使って実験してみましょう。下記のクエリを SQL Server Management Studio で実行されてみましょう。Sort オペレータが出現しているのが確認できます。

SELECT
    SalesOrderID,
    RevisionNumber,
    OrderDate,
    DueDate,
    ShipDate,
    Status,
    OnlineOrderFlag,
    SalesOrderNumber,
    PurchaseOrderNumber,
    AccountNumber,
    CustomerID,
    SalesPersonID,
    TerritoryID,
    BillToAddressID,
    ShipToAddressID,
    ShipMethodID,
    CreditCardID,
    CreditCardApprovalCode,
    CurrencyRateID,
    SubTotal,
    TaxAmt,
    Freight,
    TotalDue,
    Comment,
    rowguid,
FROM
    Sales.SalesOrderHeader WITH(FORCESEEK, INDEX(IX_SalesOrderHeader_SalesPersonID))
WHERE
    SalesPersonID = 277
ORDER BY
    OrderDate

f:id:koogucc11:20170926233446p:plain

 上記のクエリの場合、OrderDate で ORDER BY しているため、OrderDate をインデックスに含めることでインデックスによる並び替えがされている状態になるため、Sort オペレーターをなくすことが可能です。インデックスを変更してみましょう。

CREATE NONCLUSTERED INDEX IX_SalesOrderHeader_SalesPersonID ON Sales.SalesOrderHeader
(
    SalesPersonID ASC,
    OrderDate ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = ON, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)

f:id:koogucc11:20170926234214p:plain

 再度、下記のクエリを実行してみます。Sort オペレーターがなくなっていることが判断できます。

SELECT
    SalesOrderID,
    RevisionNumber,
    OrderDate,
    DueDate,
    ShipDate,
    Status,
    OnlineOrderFlag,
    SalesOrderNumber,
    PurchaseOrderNumber,
    AccountNumber,
    CustomerID,
    SalesPersonID,
    TerritoryID,
    BillToAddressID,
    ShipToAddressID,
    ShipMethodID,
    CreditCardID,
    CreditCardApprovalCode,
    CurrencyRateID,
    SubTotal,
    TaxAmt,
    Freight,
    TotalDue,
    Comment,
    rowguid,
FROM
    Sales.SalesOrderHeader WITH(FORCESEEK, INDEX(IX_SalesOrderHeader_SalesPersonID))
WHERE
    SalesPersonID = 277
ORDER BY
    OrderDate

f:id:koogucc11:20170926234428p:plain

 ついでに付加列を足せば、スッキリとした実行プランになりますね。
f:id:koogucc11:20170926235045p:plain

 実際、業務でクエリを書いていると、完全に Sort オペレーターを排除することは相当困難ではありますが....

 秋めいてきました。夏とは違った感じでビールの美味しい季節になってきました。