이 퀵스타트에서는 드라이버에 내장된 Arrow fetch 메서드를 사용하여 mssql-python SQL Server 데이터를 열형 Apache Arrow 테이블로 불러옵니다. Arrow의 열 지향 메모리 형식은 고성능 분석, pandas, Polars, DuckDB와의 제로 카피 상호 운용, 그리고 행 단위의 Python 객체를 생성하지 않고도 효율적인 Parquet 파일 I/O를 가능하게 합니다.
드라이버에는 mssql-python Windows 컴퓨터에 대한 외부 종속성이 필요하지 않습니다. 드라이버는 필요한 모든 것을 한 번 pip 에 설치해주기 때문에, 업그레이드나 테스트할 시간이 없는 다른 스크립트를 망치지 않고 최신 버전의 드라이버를 새 스크립트에 사용할 수 있습니다.
mssql-python 설명서 | mssql-python 소스 코드 | 패키지(PyPI) | Uv
사전 요구 사항
Python 3.10 이상
Python이 아직 없는 경우 python.orgPython 런타임 및 pip 패키지 관리자를 설치합니다.
사용자 고유의 환경을 사용하고 싶지 않으신가요? 컨테이너 및 로컬 개발을 따라 재현 가능한 개발 컨테이너나 GitHub Codespaces 환경을 만드세요.
macOS 및 Linux에서 암호 없는 인증을 위한 AZURE CLI(Command-Line 인터페이스)
아직 없는
uv경우 설치 지침을 따르세요.SQL Server, Azure SQL Database 또는 Fabric
AdventureWorks2025의 SQL 데이터베이스에 있는 데이터베이스로, 샘플 스키마와 유효한 연결 문자열이 포함되어 있습니다.
일회성 운영 체제 관련 필수 구성 요소를 설치합니다. Windows 사용자는 이 단계를 건너뛸 수 있습니다. 전체 플랫폼 세부사항은 Install mssql-python을 참조하세요.
SQL 데이터베이스 만들기
다음 플랫폼 중 하나에서 SQL 데이터베이스를 생성하거나 연결하세요:
프로젝트 만들기 및 코드 실행
- 새 프로젝트 만들기
- 종속성 추가
- Visual Studio Code 시작
- pyproject.toml 업데이트
- main.py를 업데이트합니다
- 연결 문자열 저장
- uv run을 사용하여 스크립트 실행
새 프로젝트 만들기
개발 디렉터리에서 명령 프롬프트를 엽니다. 디렉터리가 없다면, 예를 들어
python또는scripts와 같은 새 디렉터리를 만드세요. OneDrive에 폴더를 설치하지 마세요. 동기화가 가상 환경 관리에 방해가 될 수 있습니다.-
uv init arrow-qs cd arrow-qs
종속성 추가
같은 디렉터리에 , mssql-pythonpython-dotenvpyarrow 패키지를 rich설치하세요.
uv add mssql-python python-dotenv pyarrow rich
Visual Studio Code 시작
동일한 디렉터리에서 다음 명령을 실행합니다.
code .
pyproject.toml 업데이트
pyproject.toml 파일에는 프로젝트의 메타데이터가 포함되어 있습니다. 즐겨 찾는 편집기에서 파일을 엽니다.
파일의 내용을 검토합니다. 이 예제와 유사해야 합니다.
mssql-python의 Python 버전과 의존성을 확인하고, 최소 버전을 정의하려면>=를 사용하세요. 정확한 버전을 선호하는 경우, 버전 번호 앞의>=를==로 변경하십시오. 그런 다음 각 패키지의 확인된 버전이 uv.lock에 저장됩니다. lockfile은 프로젝트 개발자들이 일관된 패키지 버전을 사용하도록 보장합니다. 두 가지 모두pyproject.tomluv.lock커밋하고, 조직에서 승인한 의존성 스캐너를 CI에서 실행하세요.uv.lock파일을 직접 편집하지 마세요.[project] name = "arrow-qs" version = "0.1.0" description = "Add your description here" readme = "README.md" requires-python = ">=3.11" dependencies = [ "mssql-python>=1.5.0", "pyarrow>=19.0.0", "python-dotenv>=1.1.1", "rich>=14.1.0", ]설명을 더 자세히 설명하도록 업데이트합니다.
description = "Fetch SQL Server data as Apache Arrow tables using mssql-python"파일을 저장 후 닫습니다.
main.py를 수정하십시오.
라는
main.py파일을 엽니다. 이 예제와 유사해야 합니다.def main(): print("Hello from arrow-qs!") if __name__ == "__main__": main()전체 내용을 다음 코드로 바꿉니다
main.py."""Fetch SQL Server data as Apache Arrow tables using mssql-python.""" from os import getenv import pyarrow as pa import pyarrow.parquet as pq from dotenv import load_dotenv from mssql_python import connect, Connection from rich.console import Console from rich.table import Table console = Console() def get_connection() -> Connection: """Create a connection using the connection string from .env.""" load_dotenv() conn_str = getenv("SQL_CONNECTION_STRING") if not conn_str: raise ValueError("SQL_CONNECTION_STRING not set in .env file") return connect(conn_str) def fetch_arrow_table(conn: Connection) -> pa.Table: """Run a query and return the full result as an Arrow Table.""" cursor = conn.cursor() cursor.execute(""" SELECT p.ProductID, p.Name, p.ProductNumber, p.Color, p.StandardCost, p.ListPrice, p.Size, p.Weight, p.SellStartDate, pc.Name AS Category FROM SalesLT.Product AS p INNER JOIN SalesLT.ProductCategory AS pc ON p.ProductCategoryID = pc.ProductCategoryID ORDER BY p.ListPrice DESC """) arrow_table = cursor.arrow() cursor.close() return arrow_table def fetch_arrow_batches(conn: Connection) -> pa.Table: """Stream results one batch at a time using arrow_batch().""" cursor = conn.cursor() cursor.execute(""" SELECT c.CustomerID, c.CompanyName, c.EmailAddress, COUNT(soh.SalesOrderID) AS OrderCount, SUM(soh.SubTotal + soh.TaxAmt + soh.Freight) AS TotalSpent FROM SalesLT.Customer AS c LEFT OUTER JOIN SalesLT.SalesOrderHeader AS soh ON c.CustomerID = soh.CustomerID GROUP BY c.CustomerID, c.CompanyName, c.EmailAddress ORDER BY TotalSpent DESC """) batches = [] while True: batch = cursor.arrow_batch() if batch is None or batch.num_rows == 0: break batches.append(batch) cursor.close() if not batches: return pa.table({}) return pa.Table.from_batches(batches) def fetch_with_reader(conn: Connection) -> pa.Table: """Use arrow_reader() to stream results as a RecordBatchReader.""" cursor = conn.cursor() cursor.execute(""" SELECT soh.SalesOrderID, soh.OrderDate, (soh.SubTotal + soh.TaxAmt + soh.Freight) AS TotalDue, c.CompanyName FROM SalesLT.SalesOrderHeader AS soh INNER JOIN SalesLT.Customer AS c ON soh.CustomerID = c.CustomerID ORDER BY soh.OrderDate DESC """) reader = cursor.arrow_reader() arrow_table = reader.read_all() cursor.close() return arrow_table def display_arrow_table(arrow_table: pa.Table, title: str, max_rows: int = 10) -> None: """Display an Arrow table using rich formatting.""" rich_table = Table(title=title) for name in arrow_table.column_names: rich_table.add_column(name, style="bright_white") for i in range(min(max_rows, arrow_table.num_rows)): row = [str(arrow_table.column(col)[i].as_py()) for col in range(arrow_table.num_columns)] rich_table.add_row(*row) if arrow_table.num_rows > max_rows: rich_table.add_row(*[f"... ({arrow_table.num_rows - max_rows} more rows)" if col == 0 else "" for col in range(arrow_table.num_columns)]) console.print(rich_table) console.print(f"\n[dim]Schema: {arrow_table.num_columns} columns, {arrow_table.num_rows} rows[/dim]\n") def save_to_parquet(arrow_table: pa.Table, file_path: str) -> None: """Save an Arrow table to a Parquet file.""" pq.write_table(arrow_table, file_path) console.print(f"[green]Saved {arrow_table.num_rows} rows to {file_path}[/green]\n") def main() -> None: conn = get_connection() # 1. Fetch entire result as an Arrow Table with cursor.arrow() console.rule("[bold]cursor.arrow() - Full table fetch[/bold]") products = fetch_arrow_table(conn) display_arrow_table(products, "Products (Top 10 by List Price)") # 2. Stream results in batches with cursor.arrow_batch() console.rule("[bold]cursor.arrow_batch() - Batch streaming[/bold]") customers = fetch_arrow_batches(conn) display_arrow_table(customers, "Customers by Total Spent") # 3. Use RecordBatchReader with cursor.arrow_reader() console.rule("[bold]cursor.arrow_reader() - RecordBatchReader[/bold]") orders = fetch_with_reader(conn) display_arrow_table(orders, "Recent Orders") # 4. Save to Parquet console.rule("[bold]Save to Parquet[/bold]") save_to_parquet(products, "products.parquet") # 5. Read back from Parquet and verify loaded = pq.read_table("products.parquet") console.print(f"[green]Read back {loaded.num_rows} rows from products.parquet[/green]") console.print(f"[dim]Schema: {loaded.schema}[/dim]\n") conn.close() if __name__ == "__main__": main()
연결 문자열 저장
.gitignore파일을 열고.env파일에 대한 제외를 추가합니다. 파일은 이 예제와 유사해야 합니다. 완료되면 저장하고 닫아야 합니다.# Python-generated files __pycache__/ *.py[oc] build/ dist/ wheels/ *.egg-info # Virtual environments .venv # Connection strings and secrets .env # Generated data files *.parquet현재 디렉터리에서 새 파일을 만듭니다
.env..env파일 내부에서SQL_CONNECTION_STRING이라는 이름의 연결 문자열 항목을 추가합니다. 여기서 예제를 실제 연결 문자열 값으로 바꿉다.SQL_CONNECTION_STRING="Server=<server_name>;Database=<database_name>;Encrypt=yes;TrustServerCertificate=no;Authentication=ActiveDirectoryInteractive"중요합니다
.env를 로컬에만 두고 소스 제어에 포함하지 마세요. CI 및 배포 환경에서는.env를 기기 간에 복사하는 대신, 플랫폼 비밀 저장소에서 연결 문자열 또는 그 구성 요소 비밀 값을 주입하세요.팁 (조언)
사용하는 연결 문자열은 주로 연결하는 SQL 데이터베이스 유형에 따라 달라집니다. Azure SQL Database 또는 Fabric의 SQL 데이터베이스에 연결하는 경우 연결 문자열 탭에서 ODBC 연결 문자열을 사용합니다. 시나리오에 따라 인증 유형을 조정해야 할 수도 있습니다. 연결 문자열 및 해당 구문에 대한 자세한 내용은 연결 문자열 구문 참조를 참조하세요.
uv run을 사용하여 스크립트 실행
팁 (조언)
macOS에서는 Microsoft Entra 인증을 위해 ActiveDirectoryInteractive 및 ActiveDirectoryDefault가 모두 작동합니다.
ActiveDirectoryInteractive 는 스크립트를 실행할 때마다 로그인하라는 메시지를 표시합니다. 반복적인 로그인 프롬프트를 피하려면 Azure CLI에서 한 번 로그인하여 , 를 실행az login한 후 를 사용ActiveDirectoryDefault해 캐시된 자격 증명을 재사용하세요.
이전의 터미널 창이나 동일한 디렉터리에 열려 있는 새 터미널 창에서 다음 명령을 실행합니다.
uv run main.py스크립트는 세 가지 Arrow 가져오기 방법을 보여줍니다:
cursor.arrow()는 모든 행이 포함된 전체pyarrow.Table를 반환합니다. 전체 데이터셋이 메모리에 필요한 소규모에서 중간 규모의 결과 세트에 가장 적합합니다.cursor.arrow_batch()한 번에pyarrow.RecordBatch하나씩 반환합니다. 데이터를 점진적으로 처리하고 모든 것을 메모리에 로드하지 않고 처리하고 싶은 큰 결과 세트에 가장 적합합니다.cursor.arrow_reader()는 스트리밍용으로pyarrow.RecordBatchReader를 반환합니다. 파이프라인 스타일의 처리나 리더를 받는 라이브러리로 직접 전달하는 데 가장 적합합니다.
스크립트는 제품 데이터를 Parquet 파일에 저장하고 다시 읽어 왕복 여부를 확인합니다.
코드 작동 방식
Connection: 스크립트가 파일에서
.env연결 문자열을 불러와서 .을 사용하여mssql_python.connect()연결을 생성합니다.전체 테이블 가져오기:
cursor.arrow()쿼리를 실행하고 전체 결과 집합을pyarrow.Table(으)로 반환합니다. 드라이버는 Arrow C 데이터 인터페이스를 사용하여 C++ 계층의 데이터를 변환하여 Python 객체 생성을 우회하여 성능을 향상시킵니다.배치 스트리밍:
cursor.arrow_batch()는 호출당 하나의pyarrow.RecordBatch를 반환합니다. 루프는 더 이상 행이 남지 않을 때까지 배치를 수집한 뒤, 이를 하나의 테이블로 결합합니다. 이 방법은 대규모 데이터셋이나 각 배치를 독립적으로 처리하고 싶을 때 사용하세요.RecordBatchReader:
cursor.arrow_reader()는 표준 Arrow 인터페이스를 반환pyarrow.RecordBatchReader하며, 많은 라이브러리에서 직접 지원합니다.reader.read_all()를 호출하면 전체 스트림을 테이블로 소비합니다.Parquet I/O:
pyarrow.parquet.write_table()Arrow 테이블을 압축된 Parquet 파일에 저장합니다. 이 형식은 컬럼 유형을 보존하고 효율적인 부분 읽기를 지원합니다.
다음 단계
이 글들을 활용해 계속 성장하세요: