SELECT 문 다음에 행 개수가 필요합니다.최적의 SQL 접근 방식은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/243782

  •  04-07-2019
  •  | 
  •  

문제

단일 테이블(조인 없음)에서 열을 선택하려고 하는데 행 검색을 시작하기 전에 이상적으로 행 수를 계산해야 합니다.나는 필요한 정보를 제공하는 두 가지 접근 방식을 찾았습니다.

접근법 1:

SELECT COUNT( my_table.my_col ) AS row_count
  FROM my_table
 WHERE my_table.foo = 'bar'

그 다음에

SELECT my_table.my_col
  FROM my_table
 WHERE my_table.foo = 'bar'

또는 접근법 2

SELECT my_table.my_col, ( SELECT COUNT ( my_table.my_col )
                            FROM my_table
                           WHERE my_table.foo = 'bar' ) AS row_count
  FROM my_table
 WHERE my_table.foo = 'bar'

내 SQL 드라이버(SQL Native Client 9.0)에서는 SELECT 문에 SQLRowCount를 사용할 수 없지만 배열에 정보를 할당하기 전에 배열을 할당하려면 결과의 행 수를 알아야 하기 때문에 이 작업을 수행합니다.안타깝게도 동적으로 할당된 컨테이너를 사용하는 것은 내 프로그램의 이 영역에서는 옵션이 아닙니다.

다음과 같은 시나리오가 발생할 수 있다는 점이 걱정됩니다.

  • 개수에 대한 SELECT가 발생합니다.
  • 행을 추가하거나 제거하는 또 다른 명령이 발생합니다.
  • 데이터에 대한 SELECT가 발생하고 갑자기 배열의 크기가 잘못되었습니다.
    -더 나쁜 경우에는 배열 제한을 넘어서 데이터를 쓰려고 시도하여 프로그램이 중단됩니다.

접근법 2에서는 이 문제를 금지합니까?

또한 두 가지 접근 방식 중 하나가 더 빠를까요?그렇다면 어느 것입니까?

마지막으로 고려해야 할 더 나은 접근 방식이 있습니까(아마도 SQLRowCount를 사용하여 SELECT 결과의 행 수를 반환하도록 드라이버에 지시하는 방법일까요?)

질문하신 분들을 위해 언급한 SQL 드라이버(Microsoft에서 제공)와 함께 Native C++를 사용하고 있습니다.

도움이 되었습니까?

해결책

100% 확신하는 방법에는 두 가지가 있습니다. COUNT(*) 실제 쿼리는 일관된 결과를 제공합니다.

  • 결합 COUNT(*) 쿼리를 사용하여 접근 2에서와 같이 쿼리를 사용하여 예제에 표시하는 양식을 추천합니다.
  • 거래를 시작한 후 접근 1에서와 같이 두 개의 쿼리를 사용하십시오. SNAPSHOT 또는 SERIALIZABLE 격리 수준.

다른 격리 수준을 사용하면 다른 클라이언트가 생성 한 새로운 행이 현재 트랜잭션에서 볼 수있게되므로 이러한 격리 수준 중 하나를 사용하는 것이 중요합니다. MSDN 문서를 읽으십시오 SET TRANSACTION ISOLATION 자세한 사항은.

다른 팁

SQL Server를 사용하는 경우 쿼리 후 @@ rowCount 기능 (또는 결과 세트가 20 억 행 이상의 행이있는 경우 rowcount_big () 기능). 이렇게하면 이전 명령문에서 선택한 행 수 또는 삽입/업데이트/삭제 명령문에 의해 영향을받는 행의 수가 반환됩니다.

SELECT my_table.my_col
  FROM my_table
 WHERE my_table.foo = 'bar'

SELECT @@Rowcount

또는 접근 #2와 유사한 결과에 포함 된 행 카운트를 사용하려면 오버 절.

SELECT my_table.my_col,
    count(*) OVER(PARTITION BY my_table.foo) AS 'Count'
  FROM my_table
 WHERE my_table.foo = 'bar'

오버 절을 사용하면 하위 쿼리를 사용하여 행 계산을 얻는 것보다 훨씬 더 나은 성능을 얻을 수 있습니다. @@ rowCount를 사용하면 select @@ rowCount 문에 대한 쿼리 비용이 없기 때문에 최상의 성능이 있습니다.

댓글에 대한 응답으로 업데이트 : 내가 준 예제는 #을 파티션으로 제공합니다. 각 행에서 열의 값은 my_table.foo의 동일한 값을 가진 행의 #입니다. 예제 쿼리는 "my_table.foo = 'bar'"조항이 있으므로 resultSet의 모든 행은 my_table.foo와 동일한 값을 가지므로 열의 값은 모든 행에 대해 동일하고 동일합니다 (in 이 경우) 이것은 쿼리의 행입니다.

다음은 결과 세트의 총 행에 열에 열을 포함시키는 방법에 대한 더 나은/간단한 예입니다. 옵션 파티션으로 절을 제거하십시오.

SELECT my_table.my_col, count(*) OVER() AS 'Count'
  FROM my_table
 WHERE my_table.foo = 'bar'

접근 2는 항상 결과 세트와 일치하는 카운트를 반환합니다.

카운트의 조건이 데이터 세트의 조건과 일치하도록 보장하기 위해 하위 쿼리를 외부 쿼리에 연결하는 것이 좋습니다.

SELECT 
  mt.my_row,
 (SELECT COUNT(mt2.my_row) FROM my_table mt2 WHERE mt2.foo = mt.foo) as cnt
FROM my_table mt
WHERE mt.foo = 'bar';

쿼리 실행 및 결과 검색 이후 몇 밀리 초 안에 조건을 충족하는 행의 수에 관심이있는 경우 트랜잭션 내에서 쿼리를 실행할 수 있습니다.

BEGIN TRAN bogus

SELECT COUNT( my_table.my_col ) AS row_count
FROM my_table
WHERE my_table.foo = 'bar'

SELECT my_table.my_col
FROM my_table
WHERE my_table.foo = 'bar'
ROLLBACK TRAN bogus

이것은 항상 올바른 값을 반환합니다.

또한 SQL Server를 사용하는 경우 @@ rowCount를 사용하여 마지막 명령문의 영향을받는 행 수를 얻고 출력을 리디렉션 할 수 있습니다. 진짜 임시 테이블 또는 테이블 변수에 대한 쿼리이므로 모든 것을 완전히 반환 할 수 있으며 거래가 필요하지 않습니다.

DECLARE @dummy INT

SELECT my_table.my_col
INTO #temp_table
FROM my_table
WHERE my_table.foo = 'bar'

SET @dummy=@@ROWCOUNT
SELECT @dummy, * FROM #temp_table

다음은 몇 가지 아이디어입니다.

  • 접근법 #1을 사용하여 배열의 크기를 조정하여 추가 결과를 보관하거나 필요에 따라 자동으로 크기가 조정되는 유형을 사용합니다(사용 중인 언어가 무엇인지 언급하지 않았으므로 더 구체적으로 설명할 수는 없습니다).
  • 데이터베이스가 이를 지원하는 경우 트랜잭션 내에서 접근 방식 #1의 두 문을 모두 실행하여 두 번 모두 동일한 개수를 보장할 수 있습니다.
  • 데이터로 무엇을 하고 있는지 잘 모르겠지만, 먼저 결과를 모두 저장하지 않고 결과를 처리할 수 있다면 이것이 가장 좋은 방법일 수 있습니다.

SELECT COUNT와 SELECT 문 사이에서 행 카운트가 변경 될 것이라고 정말로 우려하는 경우, 먼저 행을 온도 테이블로 선택하지 않겠습니까? 그렇게하면, 당신은 당신이 동기화 될 것이라는 것을 알고 있습니다.

결과를 벡터에 넣지 않는 이유는 무엇입니까? 그렇게하면 미리 크기를 알 필요가 없습니다.

이 유형의 데이터를 다루기위한 더 나은 패턴에 대해 생각하고 싶을 수도 있습니다.

자체 전용 SQL 드라이버는 줄을 반환하기 전에 쿼리가 몇 개의 행을 반환 할 수 있는지 알려주지 않습니다. 대답이 변경 될 수 있기 때문에 (트랜잭션을 사용하지 않는 한 자체의 문제를 일으키는 경우).

행의 수는 변경되지 않습니다 -Acid 및 SQL 용 Google.

IF (@@ROWCOUNT > 0)
BEGIN
SELECT my_table.my_col
  FROM my_table
 WHERE my_table.foo = 'bar'
END

이 질문에 대한 Google에서 가장 큰 결과이기 때문에 이것을 추가하기 만하면됩니다. sqlite에서 나는 이것을 RowCount를 얻기 위해 사용했습니다.

WITH temptable AS
  (SELECT one,two
   FROM
     (SELECT one, two
      FROM table3
      WHERE dimension=0
      UNION ALL SELECT one, two
      FROM table2
      WHERE dimension=0
      UNION ALL SELECT one, two
      FROM table1
      WHERE dimension=0)
   ORDER BY date DESC)
SELECT *
FROM temptable
LEFT JOIN
  (SELECT count(*)/7 AS cnt,
                        0 AS bonus
   FROM temptable) counter
WHERE 0 = counter.bonus
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top