web-dev-qa-db-ja.com

「selecttop」のようにSQLServerに「selectlast」または「selectbottom」がないのはなぜですか?

これはおそらくばかげた質問のように聞こえるかもしれませんが、ご容赦ください。 SQLサーバーには

SELECT TOP N ...

これで、最初のn行を昇順(デフォルト)で取得できるようになりました。レコードを他の列で並べ替える場合は、orderby句で次のように指定するだけです...

SELECT TOP N ... ORDER BY [ColumnName]

さらにクール。しかし、last行が必要な場合はどうなりますか?私はこのようなものを書くだけです...

SELECT TOP N ... ORDER BY [ColumnName] DESC

しかし、それにはわずかな懸念があります。私は懸念を言ったが、実際には問題ではないのでissueではない。このようにして、その列に基づいて最後の行を取得できますが、必要に応じて挿入された最後の行SCOPE_IDENTITYIDENT_CURRENT、および@@IDENTITYについては知っていますが、heapclustered indexのないテーブル)ID列がなく、多くの場所からの複数のアクセス(pleaseは、これにあまり入り込まないでください。これらの複数の操作がいつどのように行われるかは、主なことには関係ありません)。したがって、この場合、実際に最後に挿入された行を見つける方法はeasyではないようです。一部の人はこれに次のように答えるかもしれません

[テーブル]からselect *を実行すると、SQL結果ウィンドウに表示される最後の行が最後に挿入されます。

これについて考えている人にとっては、これは実際にはそうではありません、少なくとも常にではなく、常に信頼できるものです(msdnAdvanced Scanningセクション)をお読みください。

したがって、タイトル自体のように、質問はこれに要約されます。 SQLServerに

SELECT LAST

または言う

SELECT BOTTOM

またはそのようなもので、Order Byを指定する必要がなく、クエリの実行時にテーブルに挿入された最後のレコード(ここでも詳細については説明しません)コミットされていない読み取りまたはファントム読み取りの場合、これはどのようになりますか)。

しかし、それでも、これらの読み取りレベルについて話さずにこれについて話すことはできないと誰かが主張する場合、彼らにとっては、TOPと同じように動作させることができますが、正反対です。しかし、あなたの議論がそうなら、私たちはいつもできるのでそれを必要としません

SELECT TOP N ... ORDER BY [ColumnName] DESC

それなら私はここで何を言うべきか本当にわかりません。私知っている私たちはそれを行うことができますが、関係に基づく理由、またはいくつかの意味論に基づく理由、または他の何らかの理由がありますそのため私たちは持っていませんまたはこのSELECT LAST/BOTTOMを持つことはできません。私はOrder Byを行う方法を探していません。なぜそれを持っていないか、持っていないのかについての理由を探しています。

Extra NOSQLがどのように機能するかについてはよくわかりませんが、mongodbelastic searchを(少しだけ)使用しましたが、何も表示されていないようです。このような。彼らがそれを持っていない理由は、これまで誰もそれを持っていなかったからですか、それとも何らかの理由でそれはもっともらしいものではありませんか?

[〜#〜]更新[〜#〜]

I do n't降順で順序を指定する必要があるかどうかを知る必要があります。回答またはコメントする前に、質問を読み、私の懸念を理解してください。最後の行を取得する方法を知っています。それも問題ではありません。主な質問は、対応するもののようなselect last/bottomがない理由に要約されます。

UPDATE 2

Vladimir および Pieter からの回答の後、SELECT TOPなしでORDER BYを実行すると、順序が保証されないことがわかっていることを更新したかっただけです。質問の前半で書いたことから、それが事実かどうかわからないという印象を与えるかもしれませんが、さらに下を見ると、haveへのリンクが与えられています msdn そして、SELECT TOPのないORDER BYは順序付けを保証しないと述べました。ですから、私の発言が間違っているというあなたの答えにこれを追加しないでください。私は数行後に自分自身を明らかにしました(ここでmsdnへのリンクを提供しました)。

8
Razort4x

あなたはそれをこのように考えることができます。

SELECT TOP NなしのORDER BYは、someN行を返します。最初でも最後でもありません。someだけです。どの行を返すかは定義されていません。同じステートメントを10回実行し、毎回10の異なる行セットを取得できます。

したがって、サーバーの構文がSELECT LAST Nの場合、ORDER BYを使用しないこのステートメントの結果は、やはり未定義になります。これは、SELECT TOP Nを使用しない既存のORDER BYで得られる結果とまったく同じです。


あなたは私が以下に書いたことを知っていて理解していることをあなたの質問で強調しました、しかし私はそれを後で読むすべての人のためにそれを明らかにするためにそれでも保ちます。

質問の最初のフレーズ

SQLサーバーにはSELECT TOP N ...があり、最初のn行を昇順(デフォルト)で取得できます。

正しくありません。 SELECT TOP NなしでORDER BYを使用すると、N個の「ランダム」行が取得されます。まあ、実際にはランダムではありませんが、サーバーは意図的に行から行へランダムにジャンプしません。テーブルをスキャンするための決定論的な方法を選択しますが、テーブルをスキャンする方法はさまざまであり、サーバーは必要に応じて選択したパスを自由に変更できます。これが「未定義」の意味です。

サーバーは行がテーブルに挿入された順序を追跡しないため、SELECT TOP NなしのORDER BYの結果は、テーブルに行が挿入された順序によって決定されるという仮定は正しくありません。


だから、あなたの最後の質問への答え

なぜ対応するもののようなselect last/bottomがないのですか。

は:

  • ORDER BYがないと、SELECT LAST Nの結果はSELECT TOP Nの結果とまったく同じになります-未定義。
  • ORDER BYの結果SELECT LAST N ... ORDER BY X ASCは、SELECT TOP N ... ORDER BY X DESCの結果とまったく同じです。

したがって、同じことを行う2つのキーワードを使用する意味はありません。


Pieterの答えには良い点があります。単語TOPはやや誤解を招くものです。これは、実際にはLIMIT結果がいくつかの行に設定されることを意味します。

ちなみに、SQL Server 2012以降、ANSI規格のサポートが追加されました OFFSET

OFFSET { integer_constant | offset_row_count_expression } { ROW | ROWS }
[
  FETCH { FIRST | NEXT } {integer_constant | fetch_row_count_expression } { ROW | ROWS } ONLY
]

ここで別のキーワードを追加すると、それがANSI規格[〜#〜]および[〜#〜]であることが正当化され、重要な機能が追加されます。以前は存在しませんでした。


彼の質問で [〜#〜] msdn [〜#〜] への非常に良いリンクを提供してくれた@ Razort4xに感謝します。 「高度なスキャン」セクションには、「メリーゴーランドスキャン」と呼ばれるメカニズムの優れた例があります。これは、SELECTステートメントから返される結果の順序がORDER BY句なしでは保証できない理由を示しています。

この概念はしばしば誤解されており、私はここでSOに多くの質問を見てきました。それは、そのリンクからの引用があれば非常に有益です。


あなたの質問への答え

SQL ServerにSELECT LASTがない、またはSELECT BOTTOMなどと言うことがないのはなぜですか。ここで、ORDER BYを指定する必要はなく、最後のレコードがテーブルのテーブルに挿入されます。クエリの実行時間(ここでも、コミットされていない読み取りまたはファントム読み取りの場合にこれがどのように発生するかについては詳しく説明しません)。

は:

悪魔はあなたが省略したい詳細にあります。どのレコードが「クエリの実行時にテーブルに最後に挿入された」かを知るために(そしてこれをある程度一貫した/ランダムでない方法で知るために)、サーバーはこの情報を何らかの方法で追跡する必要があります。同時に実行される複数のトランザクションのすべてのシナリオで可能であっても、パフォーマンスの観点からはコストがかかる可能性があります。すべてのSELECTがこの情報を要求するわけではありませんが(実際にはほとんど、またはまったく要求しません)、この情報を追跡するオーバーヘッドは常に存在します。

したがって、次のように考えることができます。パフォーマンスに影響するため、デフォルトでは、サーバーは行が挿入された順序を知る/追跡するための特定のことは何もしませんが、使用できることを知る必要がある場合、たとえば、IDENTITY列。 Microsoftは、すべてのテーブルにIDENTITY列が必要になるようにサーバーエンジンを設計できたはずですが、オプションにしたので、私の意見では良いと思います。サーバーよりも、どのテーブルにIDENTITY列が必要で、どれが不要かをよく知っています。

概要

SELECT LASTなしでORDER BYを2つの異なる方法で見ることができることを要約したいと思います。

1)SELECT LASTが既存のSELECT TOPに沿って動作することを期待する場合。この場合、結果はLASTTOPの両方で未定義です。つまり、結果は事実上同じです。この場合、それは別のキーワードを持っている(持っていない)ことに要約されます。言語開発者(この場合はT-SQL言語)は、正当な理由がない限り、キーワードの追加に常に消極的です。この場合、それは明らかに回避可能です。

2)SELECT LASTSELECT LAST INSERTED ROWとして動作することを期待する場合。ちなみに、これはSELECT TOPに同じ期待を拡張してSELECT FIRST INSERTED ROWとして動作するか、新しいキーワードLAST_INSERTEDFIRST_INSERTEDを追加して、既存のキーワードTOPをそのまま維持する必要があります。この場合、それはパフォーマンスに要約され、そのような動作のオーバーヘッドが追加されます。現時点では、この情報が必要ない場合、サーバーではこのパフォーマンスの低下を回避できます。必要な場合は、慎重に使用すればIDENTITYはかなり良い解決策です。

14

必要がないため、最後の選択はありません。 「テーブルからトップ1 *を選択」について考えてみます。トップ1は、返される最初の行を取得します。そして、プロセスは停止します。

ただし、byでの注文を指定しない場合、注文についての保証はありません。したがって、取得したデータセット内の任意の行である可能性もあります。

次に、「テーブルから最後の1 *を選択」を実行します。これで、データベースは最後の行を取得するためにすべての行を処理する必要があります。また、順序付けは非決定論的であるため、「トップ1」を選択した場合と同じ結果になる可能性があります。

問題がどこに来るのか今すぐわかりますか?上位と最後の順序が実際には同じでない場合、「最後」のみがより多くの時間を要します。そして、byによる注文で、本当に必要なのはトップだけです。

SELECT TOP N ...

これで、最初のn行を昇順(デフォルト)で取得できるようになりました。レコードを他の列で並べ替える場合は、orderby句で次のように指定するだけです...

ここであなたが言うことは完全に間違っており、それがどのように機能するかは絶対にありません。どのような注文をするかについての保証はありません。 whatの昇順?

create table mytest(id int, id2 int)
insert into mytest(id,id2)values(1,5),(2,4),(3,3),(4,2),(5,1)
select top 1 * from mytest
select * from mytest
create clustered index myindex on mytest(id2)
select top 1 * from mytest
select * from mytest
insert into mytest(id,id2)values(6,0)
select top 1 * from mytest

このコードを1行ずつ試して、最後の「selecttop1」で何が得られるかを確認してください。この場合は最後に挿入されたレコードが得られます。

更新

「テーブルからトップ1 *を選択する」とは、基本的に「テーブルからランダムな行を選択する」という意味だと理解していると思います。では、最後はどういう意味ですか? 「テーブルから最後のランダムな行を選択しますか?」テーブルの最後のランダムな行は、テーブルのランダムな行を1つ言うのと概念的に同じではないでしょうか。それが本当なら、トップとラストは同じなので、ラストは必要ありません。

更新2後から考えると、mysqlが使用する構文:LIMITに満足していました。 Topは、返される行数を指定するためだけに、順序付けについては何も述べていません。

SQL Server 2014では、クエリ結果セットで返される行を、指定された行数または行の割合に制限します。

3
Pieter B

SELECT LAST_INSERTEDが意味をなさない理由。

  1. ヒープ以外のテーブルには簡単に適用できません。

  2. ヒープデータはDBMSによって自由に移動できるため、これらの「自然な」順序は変更される可能性があります。それを維持するために、システムは役に立たない無駄のように見えるいくつかの追加のメカニズムを必要とします。

  3. 本当に必要な場合は、「自動インクリメント」列を追加することでシミュレートできます。

2
Matt

特に明記されていない限り、SQLServerの順序は任意です。セットベースなので、必須セットの内容を定義しますis。正しいSCOPE_IDENTITY()は、最後に挿入されたレコード、またはOUTPUT句をキャプチャする正しい方法です。とにかく時系列で参照する必要があるヒープに挿入を行うのはなぜですか?それは非常に悪いデータベース設計です。

0
John Bell