web-dev-qa-db-ja.com

「groupby」は自動的に「orderby」を保証しますか?

「groupby」句は、結果がそのキーで並べ替えられることを自動的に保証しますか?言い換えれば、次のように書くだけで十分ですか?

select * 
from table
group by a, b, c

または人は書く必要がありますか

select * 
from table
group by a, b, c
order by a, b, c

私は知っています、例えばMySQLではそうする必要はありませんが、SQL実装全体で信頼できるかどうか知りたいです。保証されていますか?

15
TMS

group byはデータを必要に応じて順序付けません。 DBは、データをできるだけ速く取得し、必要な場合にのみ並べ替えるように設計されています。

したがって、保証付きの注文が必要な場合は、order byを追加してください。

21
juergen d

Group byの効率的な実装では、データを内部で並べ替えることによってグループ化を実行します。そのため、一部のRDBMSは、グループ化時にソートされた出力を返します。それでも、SQL仕様ではその動作が義務付けられていないため、RDBMSベンダーによって明示的に文書化されていない限り、(明日)動作することに賭けません。 OTOH、RDBMSが暗黙的にソートを実行する場合、冗長な順序を最適化(回避)するのに十分賢い可能性もあります。 @ jimmyb

その概念を証明するPostgreSQLを使用した例

今日から90日までの日範囲のランダムな日付を使用して、100万レコードのテーブルを作成し、日付でインデックスを作成

CREATE TABLE WITHDRAW AS
  SELECT (random()*1000000)::integer AS IDT_WITHDRAW,
    md5(random()::text) AS NAM_PERSON,
    (NOW() - ( random() * (NOW() + '90 days' - NOW()) ))::timestamp AS DAT_CREATION, -- de hoje a 90 dias atras
    (random() * 1000)::decimal(12, 2) AS NUM_VALUE
  FROM generate_series(1,1000000);

CREATE INDEX WITHDRAW_DAT_CREATION ON WITHDRAW(DAT_CREATION);

月の日で切り捨てられた日付によるグループ化、2日間の範囲の日付による選択の制限

EXPLAIN 
SELECT
    DATE_TRUNC('DAY', W.dat_creation), COUNT(1), SUM(W.NUM_VALUE)
FROM WITHDRAW W
WHERE W.dat_creation >= (NOW() - INTERVAL '2 DAY')::timestamp
AND W.dat_creation < (NOW() - INTERVAL '1 DAY')::timestamp
GROUP BY 1

HashAggregate  (cost=11428.33..11594.13 rows=11053 width=48)
  Group Key: date_trunc('DAY'::text, dat_creation)
  ->  Bitmap Heap Scan on withdraw w  (cost=237.73..11345.44 rows=11053 width=14)
        Recheck Cond: ((dat_creation >= ((now() - '2 days'::interval))::timestamp without time zone) AND (dat_creation < ((now() - '1 day'::interval))::timestamp without time zone))
        ->  Bitmap Index Scan on withdraw_dat_creation  (cost=0.00..234.97 rows=11053 width=0)
              Index Cond: ((dat_creation >= ((now() - '2 days'::interval))::timestamp without time zone) AND (dat_creation < ((now() - '1 day'::interval))::timestamp without time zone))

より広い制限日付範囲を使用して、[〜#〜] sort [〜#〜]を適用することを選択します

EXPLAIN 
SELECT
    DATE_TRUNC('DAY', W.dat_creation), COUNT(1), SUM(W.NUM_VALUE)
FROM WITHDRAW W
WHERE W.dat_creation >= (NOW() - INTERVAL '60 DAY')::timestamp
AND W.dat_creation < (NOW() - INTERVAL '1 DAY')::timestamp
GROUP BY 1

GroupAggregate  (cost=116522.65..132918.32 rows=655827 width=48)
  Group Key: (date_trunc('DAY'::text, dat_creation))
  ->  Sort  (cost=116522.65..118162.22 rows=655827 width=14)
        Sort Key: (date_trunc('DAY'::text, dat_creation))
        ->  Seq Scan on withdraw w  (cost=0.00..41949.57 rows=655827 width=14)
              Filter: ((dat_creation >= ((now() - '60 days'::interval))::timestamp without time zone) AND (dat_creation < ((now() - '1 day'::interval))::timestamp without time zone))

最後にORDER BY 1を追加するだけです(大きな違いはありません)

GroupAggregate  (cost=116522.44..132918.06 rows=655825 width=48)
  Group Key: (date_trunc('DAY'::text, dat_creation))
  ->  Sort  (cost=116522.44..118162.00 rows=655825 width=14)
        Sort Key: (date_trunc('DAY'::text, dat_creation))
        ->  Seq Scan on withdraw w  (cost=0.00..41949.56 rows=655825 width=14)
              Filter: ((dat_creation >= ((now() - '60 days'::interval))::timestamp without time zone) AND (dat_creation < ((now() - '1 day'::interval))::timestamp without time zone))

PostgreSQL 10.3

3
deFreitas

絶対にありません。テーブル内のデータが大きくなるにつれて、クエリの1つが突然、順序付けられていない結果を返し始めたことがあります。

1
Hakan

私はそれを試してみました。 MsdnのAdventureworksdb。

select HireDate, min(JobTitle)
from AdventureWorks2016CTP3.HumanResources.Employee
group by HireDate

結果:

2009-01-10生産技術者-WC40

2009-01-11アプリケーションスペシャリスト

2009-01-12最高財務責任者のアシスタント

2009-01-13生産技術者-WC50 <

これは、hiredateのソートされたデータを返しますが、どのような状況でもGROUPBYからSORTに依存することはありません。

例えば;インデックスは、このソートされたデータを変更できます。

次のインデックスを追加しました(hiredate、jobtitle)

CREATE NONCLUSTERED INDEX NonClusturedIndex_Jobtitle_hireddate ON [HumanResources].[Employee]
(
    [JobTitle] ASC,
    [HireDate] ASC
)

同じ選択クエリで結果が変わります。

2006-06-30生産技術者-WC60

2007-01-26マーケティングアシスタント

2007-11-11エンジニアリングマネージャー

2007-12-05シニアツールデザイナー

2007-12-11ツールデザイナー

2007-12-20マーケティングマネージャー

2007-12-26生産監督者-WC60

次のアドレスからAdventureworks2016をダウンロードできます。

https://www.Microsoft.com/en-us/download/details.aspx?id=49502

0
Başar Kaya

データベースベンダーによって異なります。

たとえば、PostgreSQLはグループ化された結果を自動的にソートしません。ここでは、データを並べ替えるためにorderbyを使用する必要があります。

しかし、SybaseとMicrosoft SQLServerはそうします。ここでは、order byを使用して、デフォルトの並べ替えを変更できます。

0
Hasan Tuncay