6

SQL Server 2012 データベース内のオブジェクトからのリンク テーブルであるテーブルがあります ( annonsid, annonsid2)。このテーブルは、三角形または長方形のチェーンを作成して、誰が誰と交換できるかを確認するために使用されます。

これは、1,500 万行を含むテーブルで使用するクエリであり、このクエリを使用してMatching_IDs1,400 万の可能なチェーンを生成します。

SELECT COUNT(*)
FROM Matching_IDs AS m
  INNER JOIN Matching_IDs AS m2
     ON m.annonsid2 = m2.annonsid
  INNER JOIN Matching_IDs AS m3
     ON m2.annonsid2 = m3.annonsid
       AND m.annonsid = m3.annonsid2

おそらく 1 秒以下になるようにパフォーマンスを改善する必要があります。これを行うより速い方法はありますか? 私のコンピューターでは、クエリに約 1 分かかります。私は通常 a を使用しますがWHERE m.annonsid=x、とにかくすべての可能な組み合わせを実行する必要があるため、同じ時間がかかります。

更新: 最新のクエリ プラン

|--Compute Scalar(DEFINE:([Expr1006]=CONVERT_IMPLICIT(int,[globalagg1011],0)))
   |--Stream Aggregate(DEFINE:([globalagg1011]=SUM([partialagg1010])))
        |--Parallelism(Gather Streams)
             |--Stream Aggregate(DEFINE:([partialagg1010]=Count(*)))
                  |--Hash Match(Inner Join, HASH:([m2].[annonsid2], [m2].[annonsid])=([m3].[annonsid], [m].[annonsid2]), RESIDUAL:([MyDatabase].[dbo].[Matching_IDs].[annonsid2] as [m2].[annonsid2]=[MyDatabase].[dbo].[Matching_IDs].[annonsid] as [m3].[annonsid] AND [MyDatabase].[dbo].[Matching_IDs].[annonsid2] as [m].[annonsid2]=[MyDatabase].[dbo].[Matching_IDs].[annonsid] as [m2].[annonsid]))
                       |--Parallelism(Repartition Streams, Hash Partitioning, PARTITION COLUMNS:([m2].[annonsid2], [m2].[annonsid]))
                       |    |--Index Scan(OBJECT:([MyDatabase].[dbo].[Matching_IDs].[NonClusteredIndex-20121229-133207] AS [m2]))
                       |--Parallelism(Repartition Streams, Hash Partitioning, PARTITION COLUMNS:([m3].[annonsid], [m].[annonsid2]))
                            |--Merge Join(Inner Join, MANY-TO-MANY MERGE:([m].[annonsid])=([m3].[annonsid2]), RESIDUAL:([MyDatabase].[dbo].[Matching_IDs].[annonsid] as [m].[annonsid]=[MyDatabase].[dbo].[Matching_IDs].[annonsid2] as [m3].[annonsid2]))
                                 |--Parallelism(Repartition Streams, Hash Partitioning, PARTITION COLUMNS:([m].[annonsid]), ORDER BY:([m].[annonsid] ASC))
                                 |    |--Index Scan(OBJECT:([MyDatabase].[dbo].[Matching_IDs].[NonClusteredIndex-20121229-133152] AS [m]), ORDERED FORWARD)
                                 |--Parallelism(Repartition Streams, Hash Partitioning, PARTITION COLUMNS:([m3].[annonsid2]), ORDER BY:([m3].[annonsid2] ASC))
                                      |--Index Scan(OBJECT:([MyDatabase].[dbo].[Matching_IDs].[NonClusteredIndex-20121229-133207] AS [m3]), ORDERED FORWARD)
4

5 に答える 5

3

いくつかのアイデア:

2 つのインデックス (annonsid,annonsid2) と (annonsid2,annonsid) を試す

列ストア インデックスを試しましたか? テーブルを読み取り専用にしますが、パフォーマンスが向上する可能性があります。

また、クエリのいくつかのバリエーションが役立つ場合があります。例:

SELECT COUNT(*)
FROM Matching_IDs AS m
  INNER JOIN Matching_IDs AS m2
     ON m.annonsid2 = m2.annonsid
  INNER JOIN Matching_IDs AS m3
     ON m2.annonsid2 = m3.annonsid
where m.annonsid = m3.annonsid2

また

SELECT COUNT(*)
FROM Matching_IDs AS m, Matching_IDs AS m2, Matching_IDs AS m3
where m2.annonsid2 = m3.annonsid
  and m.annonsid2 = m2.annonsid
  and m.annonsid = m3.annonsid2

CPU/IO負荷を確認しましたか? IO-Load が高い場合、サーバーは数値を処理していませんが、スワッピング => RAM を増やすことで問題が解決します。

このクエリの速度は?

SELECT COUNT(*)
FROM Matching_IDs AS m
  INNER JOIN Matching_IDs AS m2
     ON m.annonsid2 = m2.annonsid

これが非常に高速であるが、次の結合を追加すると速度が低下する場合は、おそらくより多くの RAM が必要です。

于 2012-12-30T09:47:36.920 に答える
1

あなたはすでにこれをかなりうまく索引付けしているようです。適切な複数列インデックスを追加して、ハッシュをマージ結合に変換してみることができますが、希望する 60 倍の高速化は得られません。

annonsid, annonsid2ここで間違いを犯したかもしれませんが、このインデックスはオンになると思います。

これらすべてを具体化できればよいのですが、インデックス付きビューは自己結合をサポートしていません。このクエリ (未集計) を新しいテーブルに実体化することを試みることができます。ベース テーブルに対して DML を実行するたびに、2 番目のテーブルも更新します (アプリケーション ロジックまたはトリガーのいずれかを使用)。これにより、非常に高速にクエリを実行できます。

于 2012-12-29T23:54:20.257 に答える
1

このクエリをもう少し分離する必要があります。最初に、主キー + annonsid、annonsid2 を格納できるテーブルを作成する必要があると思います - annosid が主キー自体でない場合

DECLARE @AnnonsIds TABLE
(
primaryKey int,
-- if you need later more info from the original rows like captions  
-- AND it is not (just) the annonsid
annonsid int,
annonsid2 int
)

テーブルを宣言し、この列にインデックスがある場合、指定された行を取得するのは非常に高速です。WHERE annonsid = @annonsid OR annonsid2 = @annosid

最初のステップの後、作業するテーブルがはるかに小さく (おそらく)、「薄い」テーブルになります。次に、ここで結合を使用するか、一時テーブルと CTE を作成するだけです。

の条件の選択性に応じて、より高速になるはずだと思いますが、WHERE110万行が収まる場合は意味がありませんが、数百または数千行しかない場合は、試してみてください。 !

于 2012-12-30T07:36:32.730 に答える
0

、およびを使用してテーブルRelatedIdsを追加することにより、データを非正規化できます。テーブルのすべての値には、それぞれの行と、それに到達するためにトラバースする必要があるリレーションの数が含まれます。既存のテーブルのトリガーは、長方形のシェアを処理するために 3 など、いくつかの構成された最大値を持つ新しいテーブルを維持します。( 、 )でテーブルにインデックスを付けます。AnnonsIdRelatedAnnonIdDistanceAnnonsIdRelatedAnnonIdDistanceMatchingIdsDistanceAnnonsIdDistance

編集:Distance ( , )のインデックスAnnonsIdを使用すると、特定の形状を形成するのに十分な関連エントリを持つ行をすばやく見つけることができます。たとえば、長方形ではなくMaxDistance三角形の関係があることに基づいて行を除外できるようにする場合は、列を追加すると便利です。

新しいクエリはinner join RelatedIds as RI on RI.AnnonsId = m.AnnonsId and RI.Distance <= @MaxDistance、の値を指示する目的の「形状」を使用します@MaxDistance

でのパフォーマンスが大幅に向上するはずselectです。欠点は、多数の行を持つ別のテーブルと、テーブルを変更するときのトリガーのオーバーヘッドですMatchingIds

例: にはMatching_IDs(1,2) と (2,3) の 2 つのエントリがあります。新しいテーブルには 3 つのエントリが含まれます:
1-> 2: 距離 = 1
1-> 3: 距離 = 2 (1 から 3 に移動するには、1 つの中間「ノード」が必要です)
2-> 3: 距離 = 1

一致する ID (3,1) にもう 1 つのエントリを追加すると、別のエントリが生成されます:
1-> 1: 距離 = 3

そして出来上がり: 三角形が見つかりました (距離 = 3)。

ここで、すべての三角形を見つけるには、次のようにします。

select * 
  from RelatedIds 
 where AnnonsId=RelatedAnnonId 
   and Distance=3
于 2012-12-30T19:46:22.360 に答える
0

1 - 選択Count(*)Count(1) または に変更Count(id)

set Nocount on 2 -ストアド プロシージャの最初またはクエリの最初に書き込み ます

3 - でインデックスをannonsid使用annonsid2

4 - テーブルの主キーの後にインデックスを配置する

于 2012-12-31T07:42:34.513 に答える