- SQL과 Python을 결합하면 강력한 엔드투엔드 데이터 워크플로우를 구현할 수 있지만, 연결, 종속성 및 버전 관련 문제점이 발생할 수 있습니다.
- SQL Server 머신 러닝 서비스는 엔진 내부에 R/Python을 추가하지만, 설치, 런타임 및 데이터 유형과 관련하여 여러 가지 주의 사항이 있습니다.
- SQLite 또는 다른 RDBMS에서 실제 관계를 모델링할 때는 기본 키와 외래 키, 그리고 JOIN을 포함하는 정규화된 스키마가 필수적입니다.
- 안정적이고 고성능의 SQL-Python 통합을 위해서는 드라이버 설정, 타입 처리 및 리소스 관리에 세심한 주의를 기울여야 합니다.
SQL과 Python을 함께 사용하는 것은 데이터 및 백엔드 개발에서 가장 강력한 조합 중 하나입니다.하지만 이는 또한 수많은 미묘한 오류, 구성 함정 및 예상치 못한 성능 문제로 이어질 수 있습니다. 데이터베이스 연결이 "당연히 작동해야 하는데" 이해하기 어려운 오류 메시지를 마주하거나, 동일한 분석 스크립트가 노트북에서는 매우 빠르게 실행되지만 SQL Server에서는 느리게 실행되는 이유가 궁금했던 적이 있다면, 당신은 혼자가 아닙니다.
이 가이드는 실제 SQL-Python 문제, SQL Server 머신 러닝 서비스의 저수준 문제, 그리고 분석에서 두 언어를 사용하는 실용적인 패턴을 종합적으로 다룹니다.모호한 조언 대신 구체적인 예제, 일반적인 오류 메시지, 문제 진단 및 해결을 위한 단계별 아이디어는 물론 SQLite 및 기타 엔진을 사용하여 Python에서 데이터베이스를 설계, 쿼리 및 조작하는 방법에 대한 전체 과정을 제공합니다.
SQL과 Python 간의 일반적인 연결 문제
SQL과 Python을 함께 사용할 때 가장 먼저 겪는 어려움 중 하나는 안정적인 연결을 확보하는 것입니다.자격 증명과 DSN이 올바르게 보이더라도 드라이버, 경로 또는 환경의 작은 불일치로 인해 app.py를 시작하거나 명령줄에서 스크립트를 실행하는 순간 혼란스러운 런타임 오류가 발생할 수 있습니다.
가상화 환경에서는 이러한 현상이 더욱 취약해집니다.예를 들어, 호스트 운영 체제에서 개발하면서 가상 머신 내에서 SQLite 또는 SQL Server를 실행하고 SQL Developer 또는 SQL Server Management Studio와 같은 GUI 도구를 사용하여 연결을 테스트할 수 있습니다. GUI는 제대로 연결되지만 Python 스크립트는 다른 드라이버를 사용하거나, 필요한 라이브러리가 없거나, 네트워크 경로가 완전히 다르기 때문에 연결에 실패할 수 있습니다.
일반적인 연결 문제에는 ODBC/DB API 드라이버 누락, 잘못된 DSN 구성, 포트 차단 및 인증 모드 불일치가 포함됩니다.파이썬에서 "연결할 수 없습니다"와 같은 일반적인 예외가 발생하는 것은 매우 흔한 일인데, 근본적인 문제는 시스템이 공유 라이브러리(예: Linux의 libc++ 또는 libc++abi)를 로드할 수 없거나 SQLite, PostgreSQL, MySQL 또는 SQL Server에 필요한 ODBC 드라이버를 찾지 못하는 것입니다.
파이썬에서 연결할 때는 일반적으로 sqlite3, psycopg2, pyodbc, mysql-connector-python, PyMySQL과 같은 라이브러리나 SQLAlchemy와 같은 ORM 레이어를 사용합니다.각 드라이버는 고유한 연결 문자열 형식, 오류 유형 및 종속성을 가지고 있습니다. GUI 클라이언트는 이러한 문제를 숨기는 다른 드라이버 스택을 사용할 수 있으므로 Python 코드가 사용하는 정확한 드라이버 및 연결 매개변수를 항상 확인해야 합니다.
SQL과 Python을 결합하는 것이 전략적으로 강력한 이유
기술적인 어려움 외에도, 개발자와 분석가들이 파이썬과 SQL을 결합하는 것을 고집하는 데에는 전략적인 이유가 있습니다.각 언어는 데이터 수명주기의 서로 다른 부분을 다루며, 이들을 함께 사용하면 단일 도구로는 따라잡기 어려운 엔드투엔드 워크플로우를 제공합니다.
SQL은 여전히 관계형 데이터 관리의 표준입니다.SQL은 잘 구조화된 데이터, 관계형 무결성, 인덱싱 및 트랜잭션 워크로드 처리에 탁월합니다. SQL을 사용하면 대규모 데이터 세트에 대한 빠른 필터링, 조인 및 집계, 다양한 도구에 대한 통합 액세스, 그리고 수십 년간의 데이터베이스 연구를 통해 입증된 예측 가능한 성능을 얻을 수 있습니다.
파이썬은 데이터가 데이터베이스 컨텍스트를 벗어난 후에야 진가를 발휘합니다.pandas, NumPy, matplotlib, seaborn과 같은 라이브러리를 사용하면 데이터를 임의로 복잡한 방식으로 정리, 재구성 및 분석하고, 통계 또는 머신 러닝을 실행하고, 시각화 또는 보고서를 프로그래밍 방식으로 구축할 수 있습니다. 실시간 데이터 분석SQL에서 어색하거나 장황한 많은 변환 작업이 파이썬에서는 간단한 표현식으로 변환됩니다.
실제로 이는 명확한 분업을 의미합니다.필터링, 집계 및 기본 변환 작업을 최대한 SQL에서 수행한 다음, 정리된 데이터 세트를 다시 Python으로 가져와 심층 분석, 모델링 또는 시각화 작업을 진행합니다. 두 언어에 모두 능숙한 분석가와 엔지니어는 비즈니스 질문에서 재현 가능한 데이터 파이프라인으로 신속하게 전환할 수 있습니다.
Python과 SQL 데이터베이스 연결: 라이브러리 및 패턴
SQL과 Python을 안정적으로 연동하려면 적절한 커넥터와 데이터베이스 세션을 열고 사용하고 닫는 방식에 대한 체계적인 관리가 필요합니다.정확한 기술 스택은 데이터베이스 엔진에 따라 다르지만 개념은 유사합니다.
경량의 임베디드 워크플로우에는 SQLite가 가장 간단한 선택인 경우가 많습니다.파이썬은 표준 라이브러리에 sqlite3 모듈을 포함하고 있으므로, 추가 소프트웨어를 설치하지 않고도 데이터베이스 파일을 생성하고, 테이블을 정의하고, 쿼리를 실행할 수 있습니다. 이는 프로토타입 제작, 소규모 분석 프로젝트 또는 관계형 데이터베이스 개념 교육에 매우 적합합니다.
서버급 데이터베이스의 경우 일반적으로 엔진별 드라이버 또는 ORM을 사용합니다.PostgreSQL은 psycopg2와 함께 널리 사용되고, SQL Server는 종종 pyodbc 또는 Microsoft의 ODBC 드라이버를 통해 사용되며, MySQL/MariaDB는 mysql-connector-python 또는 PyMySQL에 의존합니다. 이러한 환경 위에 SQLAlchemy는 이식성이 뛰어난 SQL 표현식을 작성하고 연결 풀을 관리할 수 있는 고수준 추상화 계층을 제공합니다.
안정적인 연결 패턴은 환경 변수 또는 비밀 관리자에서 자격 증명을 읽어오고, 인젝션을 방지하기 위해 매개변수화된 쿼리를 사용하며, 적절한 오류 처리를 적용하는 것을 포함합니다.각 작업 단위가 완료되면 유휴 세션을 여러 개 열어두는 대신, 트랜잭션을 명시적으로 커밋하거나 롤백하고 연결을 풀로 반환하거나 닫아야 합니다.
SQLAlchemy와 pandas를 사용하면 워크플로가 특히 원활해집니다.연결 URL을 구성하고, 엔진을 생성한 다음, pandas.read_sql_query를 사용하여 쿼리 결과를 DataFrame으로 직접 가져옵니다. 그 후에는 파이썬 생태계의 모든 기능을 활용하여 데이터를 정리, 분석 및 내보낼 수 있습니다.
SQL Server의 머신 러닝 서비스: R 및 Python 통합 문제
Microsoft SQL Server에는 데이터베이스 엔진 내부에 R 및 Python 런타임을 내장하는 머신 러닝 서비스라는 기능이 포함되어 있습니다.sp_execute_external_script를 통해 외부 스크립트를 호출할 수 있습니다. 이는 데이터베이스 내 분석에 강력한 기능이지만, 버전별로 해결해야 할 버그와 제약 조건이 많습니다.
SQL Server 2016, 2017, 2019 및 2022 버전에서는 설치 및 업그레이드 문제가 특히 자주 발생합니다.문제는 특정 Azure VM 이미지에서 R 구성 요소가 누락되는 것부터 초기 SQL Server 2017 빌드에서 Python 설치 프로그램이 불완전한 것, 오프라인 R 업데이트를 묻는 메시지가 표시되지 않는 누적 업데이트(CU) 패키지에 이르기까지 다양합니다. 경우에 따라 설치 프로그램이 캐시된 CAB 파일을 가리키도록 명령줄에 MRCACHEDIRECTORY와 같은 추가 매개변수를 전달해야 합니다.
플랫폼별 종속성 문제도 있습니다.SQL Server 2019 이상 버전의 Linux 빌드에서 R 및 Python 런타임이 시작되지 않는 문제가 발생할 수 있습니다. 이는 libc++.so.1 또는 libc++abi.so.1과 같은 공유 라이브러리가 확장 라이브러리 경로에 없기 때문입니다. 이러한 문제는 SQL Server에서 "런타임과 통신할 수 없습니다"라는 일반적인 오류 메시지로 나타나는 경우가 많으며, 런치패드 로그에는 누락된 .so 파일이 표시됩니다. 일반적으로 이 문제를 해결하려면 필요한 공유 라이브러리를 /opt/mssql-extensibility/lib 디렉터리에 복사하거나 mssql.conf 파일을 통해 디렉터리를 노출시키면 됩니다.
FIPS 암호화 설정이 적용된 Windows 서버에서는 또 다른 유형의 설치 오류가 발생합니다.머신 러닝 서비스 또는 언어 확장을 활성화하려고 하면 AppContainer 생성이 Windows 플랫폼 FIPS 검증 알고리즘과 호환되지 않는다는 오류가 발생할 수 있습니다. 해결 방법은 FIPS를 일시적으로 비활성화하고 설치 또는 업그레이드를 완료한 다음 SQL Server 구성이 완전히 완료된 후 FIPS를 다시 활성화하는 것입니다.
일부 누적 업데이트는 스크립트 실행에 영향을 미치는 일시적인 오류를 발생시킬 수 있습니다.예를 들어, SQL Server 2017 CU 5~7에는 임시 디렉터리 경로에 공백이 포함된 경우 R 스크립트가 "R_TempDir을 만들 수 없습니다"라는 오류와 함께 실패하는 rlauncher.config의 버그가 있었습니다. 이후 CU에서 이 문제가 수정되었지만, 그 전까지 관리자는 RegisterRExt.exe를 사용하여 제거 및 설치 플래그와 함께 외부 스크립팅 환경을 다시 등록해야 했습니다.
클라이언트와 서버 런타임 간의 버전 불일치
또 다른 흔한 혼란의 원인은 클라이언트 도구(Microsoft R 클라이언트 또는 Python 패키지)와 서버 측 런타임(R 서버 또는 SQL Server 머신 러닝 서비스) 간의 버전 호환성 문제입니다.클라이언트에서 이전 버전의 SQL Server 인스턴스를 대상으로 원격 스크립트를 실행할 때, 버전 불일치로 인해 명시적인 오류가 발생하거나 미묘한 직렬화 문제가 발생할 수 있습니다.
SQL Server 2016 R 서비스에서 클라이언트와 서버의 R 라이브러리 버전이 정확히 일치해야 합니다.R 서버 8.0.3이 설치된 서버에서 Microsoft R 클라이언트 9.x를 실행하면 클라이언트가 호환되지 않는다는 메시지가 표시되고 호환되는 버전을 설치하라는 안내가 나옵니다. 이후 버전에서는 이러한 요구 사항이 완화되었지만, 이러한 오류가 발생하는 경우 양쪽 모두 호환성을 확인하고 서버를 업그레이드하거나 호환되는 클라이언트를 설치해야 합니다.
학습된 모델의 직렬화 및 역직렬화는 버전 차이에 특히 민감합니다.R의 RevoScaleR과 Python의 revoscalepy를 사용할 때, 최신 API로 직렬화된 모델이 이전 직렬화 인프라를 사용하는 서버에서 역직렬화에 실패하여 R에서는 memDecompress 오류, Python에서는 rx_unserialize_model이 정의되지 않았을 때 NameError와 같은 내부 오류가 발생할 수 있습니다. 일반적으로 SQL Server 2017의 경우 SQL Server 인스턴스를 CU3 이상으로 업그레이드하면 이러한 문제가 해결됩니다.
SQL Server 2017에 설치된 사전 학습된 모델도 경로 길이 제한에 걸릴 수 있습니다.초기 빌드에서는 모델 바이너리가 기본 인스턴스 경로 아래의 깊은 디렉터리 구조에 저장되었는데, 전체 경로가 운영 체제 제한을 초과하여 Python이 해당 파일을 열 수 없었습니다. 제안된 해결 방법으로는 모델을 더 짧은 사용자 지정 경로에 설치하거나, SQL Server를 더 짧은 루트 디렉터리에 설치하거나, fsutil을 사용하여 NTFS 하드 링크를 생성하여 동일한 파일에 대한 더 짧은 별칭을 노출하는 방법 등이 있었습니다.
SQL Server Machine Learning Services를 사용하여 솔루션을 설계할 때는 배포 계획의 일부로 버전 및 CU 레벨을 반드시 확정해야 합니다.CU 레벨이 서로 다른 여러 서버에 스크립트를 분산시키면서 이러한 세부 정보를 추적하지 않으면 나중에 디버깅하기 어려운 직렬화 및 런타임 문제가 발생할 수 있습니다.
리소스 관리, 성능 및 콜드 스타트 동작
SQL Server Machine Learning Services가 올바르게 설치되고 버전이 일치하더라도 리소스 관리 및 프로세스 풀링으로 인해 성능 한계에 도달할 수 있습니다.발사대와 위성 프로세스의 동작 방식을 이해하는 것은 일관된 지연 시간을 제공하는 데 핵심입니다.
SQL Server는 외부 스크립트를 위해 사용자별, 데이터베이스별, 언어별 프로세스 풀을 생성합니다.일정 시간 동안 활동이 없다가 sp_execute_external_script를 처음 호출하면 Launchpad가 R 또는 Python용 새 위성 프로세스를 시작합니다. 이러한 콜드 스타트는 부하가 심한 서버나 제약이 있는 가상 머신에서 눈에 띄게 느릴 수 있습니다. 이후 호출에서는 워밍업된 프로세스 풀을 재사용하므로 두 번째 및 세 번째 실행은 훨씬 빠릅니다.
실시간 스코어링 시나리오와 같이 첫 호출 지연 시간이 중요한 문제라면, 주기적으로 간단한 스크립트를 실행하여 풀을 활성화 상태로 유지할 수 있습니다.많은 팀에서 SQL Agent를 통해 몇 분마다 실행되도록 간단한 "아무 작업도 하지 않는" R 또는 Python 스크립트를 예약하여 유휴 정리 작업으로 인해 위성 프로세스가 종료되는 것을 방지합니다.
SQL Server 2016 Enterprise Edition의 초기 빌드에서는 외부 스크립트 메모리가 전체 RAM의 약 20%로 제한되었습니다.32GB 서버의 경우 R 실행 파일의 크기는 요청당 약 6.4GB로 제한될 수 있습니다. 대규모 모델이나 방대한 데이터셋의 경우 이는 빠르게 제약 조건이 되어 메모리 할당 오류나 심각한 페이징 문제를 야기할 수 있습니다. 관리자는 복잡한 머신러닝 워크로드가 예상되는 경우 현재 기본 설정을 검토하고 리소스 관리 설정을 조정해야 합니다.
병렬성 또한 미묘한 제약 조건 중 하나입니다.SQL Server 외부(예: RGui)에서 Microsoft ML 또는 RevoScaleR 라이브러리를 호출할 경우, 기본 에디션이 Enterprise이더라도 해당 라이브러리는 종종 단일 스레드 모드로 작동합니다. 마찬가지로, SQL Server 2019에는 RxLocalPar 컨텍스트 또는 기본 병렬 패키지를 사용하는 R 스크립트가 샌드박스 런타임에서 null 장치에 쓰기 문제를 일으켜 SQL Server가 멈추는 버그가 있었습니다.
외부 스크립트 호출 시 데이터 유형, 인코딩 및 스키마 제약 조건
sp_execute_external_script를 통해 SQL 데이터를 R 또는 Python으로 파이프라인 처리할 때 데이터 유형 및 인코딩은 예기치 않은 동작의 주요 원인입니다.모든 SQL 유형이 지원되는 것은 아니며, 일부는 부분적으로만 지원되거나 자동으로 변환되어 특히 복잡한 구조의 경우 정밀도 손실이나 문자열 손상이 발생할 수 있습니다. SQL의 배열.
이전 SQL Server 2017 누적 업데이트(CU)에서는 Python 출력 스키마에 대해 숫자, 소수 및 통화 유형에 대한 강력한 제한이 있었습니다.WITH RESULT SETS 및 Python과 함께 사용할 경우, 지원되지 않는 데이터 유형으로 인해 SqlSatelliteCall 오류와 함께 bit, smallint, int, datetime, smallmoney, real 및 float(일부 char/varchar 포함)만 허용된다는 메시지가 표시되었습니다. 이후 CU에서 이 문제가 해결되었지만, 외부 런타임에 노출하는 데이터 유형에 여전히 주의해야 합니다.
R 스크립트에서 money, numeric, decimal 및 bigint는 모두 R의 숫자형 데이터 타입으로 변환됩니다.결과적으로, 큰 값이나 소수점 이하 자릿수가 많은 값은 정밀도를 잃을 수 있습니다. 금액 유형은 센트 값을 정확하게 표현할 수 없다는 경고를 발생시킬 수 있으며, bigint는 R에서 53비트 정수 제한을 초과하여 최하위 비트에서 반올림이 발생합니다.
문자열 인코딩도 중요합니다.varchar 열에 저장된 유니코드 데이터를 전달하면 SQL Server의 데이터 정렬 방식이 R 또는 Python에서 예상하는 UTF-8 인코딩과 일치하지 않아 비ASCII 문자가 손상될 수 있습니다. 권장되는 방법은 SQL Server 2019 이상에서 사용할 수 있는 UTF-8 데이터 정렬 방식을 사용하거나 유니코드 텍스트를 nvarchar에 저장하고 스크립트에서 명시적으로 변환을 처리하는 것입니다.
일부 SQL 기능은 외부 스크립트에서 완전히 사용이 금지되어 있습니다.특정 상황에서는 Always Encrypted 열이나 마스킹된 열을 참조하는 쿼리를 R 스크립트에 직접 입력할 수 없습니다. 분석을 위해 보호된 데이터를 암호화 또는 마스킹이 적용되지 않은 임시 테이블로 복사해야 할 수 있습니다. 또한 SQL Server 컴퓨팅 환경에서는 R의 colClasses와 같은 인수가 열 형식을 재정의할 수 없습니다. 데이터를 R로 전달하기 전에 T-SQL에서 CAST 또는 CONVERT를 사용해야 합니다.
바이너리 페이로드에도 특별한 규칙이 적용됩니다.R의 원시(raw) 데이터 형식을 반환할 때는 출력 매개변수에 바인딩하는 대신 출력 데이터 프레임에 값을 포함시켜야 합니다. 실질적으로 지원되는 원시 출력 세트는 하나뿐입니다. 여러 개의 바이너리 출력이 필요한 경우 저장 프로시저를 여러 번 호출하거나 스크립트 내부에서 ODBC를 통해 SQL로 데이터를 푸시해야 할 수 있습니다.
SQL Server에 Python을 설치하고 확장할 때 발생하는 실제적인 문제점
SQL Server Machine Learning Services에 포함된 Python 환경을 설치하고 확장하는 것은 독립형 Anaconda 또는 시스템 Python보다 제약이 더 많습니다.특히 SQL Server 2019가 설치된 Windows 환경에서 많은 사용자가 pip 또는 sqlmlutils를 사용하여 패키지를 추가하려고 할 때 오류를 경험합니다.
Windows 환경에서 SQL Server 2019를 설치한 후 흔히 발생하는 문제 중 하나는 pip가 TLS/SSL 구성 문제를 보고하는 것입니다.파이썬을 실행할 수 있음에도 불구하고 SSL 모듈을 사용할 수 없다는 오류 메시지가 나타납니다. 이는 일반적으로 PYTHON_SERVICES의 DLLs 하위 디렉터리에 OpenSSL DLL(libssl-1_1-x64.dll 및 libcrypto-1_1-x64.dll)이 누락되었기 때문입니다. Library\bin 폴더에서 해당 파일을 DLLs 디렉터리로 복사한 다음 새 명령 프롬프트를 실행하면 pip가 HTTPS 요청을 수행할 수 있게 되는 경우가 많습니다.
텐서플로우와 같은 일부 인기 있는 머신러닝 패키지는 호환되지 않는 종속성 요구 사항을 가지고 있습니다.TensorFlow 휠을 사용하려면 SQL Server의 Python 환경에 사전 설치된 NumPy 버전보다 최신 버전이 필요할 수 있습니다. NumPy는 시스템 패키지로 취급되므로 sqlmlutils를 통해 업그레이드할 수 없으며, 따라서 해당 경로를 통해 TensorFlow를 설치하려고 하면 실패합니다. 대신, `-m pip` 옵션을 사용하여 PYTHON_SERVICES 실행 파일을 직접 실행하고 해당 환경에서 패키지를 업그레이드하거나 설치해야 합니다. 경우에 따라 Microsoft Visual C++와 같은 재배포 가능 런타임을 수동으로 업데이트해야 할 수도 있습니다.
리눅스에서는 pip에 포함된 진입점을 별도의 설정 없이 바로 사용할 수 있습니다.SQL Server 2019의 경우, /opt/mssql/mlservices/runtime/python/bin에서 pip를 실행하면 존재하지 않는 레거시 ML Server 위치를 가리키는 잘못된 인터프리터 오류와 함께 충돌이 발생할 수 있습니다. 해결 방법은 PyPA에서 get-pip.py를 다운로드하고 /opt/mssql/mlservices/bin/python/python에 있는 올바른 Python 바이너리와 함께 실행하여 해당 런타임에 맞게 pip를 다시 부트스트랩하는 것입니다.
파이썬 스크립트에서 varbinary 및 varchar 출력 매개변수와 관련된 미묘한 동작들도 있습니다.sp_execute_external_script 호출에서 varbinary(max) 또는 large varchar 형식의 OUTPUT 매개변수를 노출하고 Python 스크립트 내에서 값을 할당하지 않으면 BxlServer 구성 요소에서 오류가 발생하고 작동이 중지될 수 있습니다. 안전한 방법은 Python 코드 내에서 해당 매개변수를 명시적으로 초기화하는 것입니다. 빈 문자열이나 0x0으로 설정하는 경우에도 마찬가지입니다.
SQLite를 사용한 기존 SQL + Python 워크플로
SQL Server에 대한 구체적인 내용을 잠시 접어두고, SQL-Python 통합을 배우고 프로토타입을 만드는 매우 효과적인 방법은 Python의 sqlite3 모듈과 함께 SQLite를 사용하는 것입니다.SQLite는 데이터를 단일 파일에 저장하고, 별도의 서버 프로세스가 필요하지 않으며, SQL을 지원하는 소규모 관계형 데이터베이스처럼 작동합니다.
SQLite에서 데이터베이스는 디스크에 구조화된 데이터를 저장하는 정리된 파일일 뿐입니다.파이썬 딕셔너리와 유사하게 키와 값을 매핑하지만, 인덱싱, 대규모 데이터 세트를 위한 효율적인 저장 방식, 그리고 쿼리 기능을 추가합니다. 구조는 테이블(스프레드시트와 유사), 행(레코드), 열(필드)을 중심으로 구성됩니다. 보다 공식적인 관계형 용어로는 관계, 튜플, 속성이라고 합니다.
먼저 sqlite3.connect를 사용하여 데이터베이스 파일에 연결합니다.파일이 존재하지 않으면 SQLite가 파일을 생성합니다. 연결을 통해 SQL 명령을 실행하고 결과를 반복 처리하는 핸들 역할을 하는 커서 객체를 생성합니다. 이 워크플로는 파일을 열고 한 줄씩 읽는 것과 유사하지만, 일반 텍스트를 읽는 대신 SQL 문을 실행한다는 점이 다릅니다.
테이블을 생성하려면 열 이름과 데이터 형식을 지정해야 합니다.SQLite는 타입 지정에 있어 상당히 유연하지만, 타입을 명확히 정의하면 엔진이 효율적인 저장 형식과 인덱싱 전략을 선택하는 데 도움이 됩니다. 예를 들어, 간단한 노래 테이블은 텍스트 제목과 정수 재생 횟수를 타입으로 정의할 수 있습니다. `CREATE TABLE` 문으로 테이블을 생성한 후에는 `INSERT` 문과 매개변수 자리 표시자(물음표)를 사용하여 파이썬 값을 안전하게 바인딩하여 행을 삽입할 수 있습니다.
파이썬에서 SQL 사용하기: 삽입, 선택, 업데이트, 삭제
SQL은 INSERT, SELECT, UPDATE, DELETE라는 네 가지 핵심 연산을 제공하며, 이는 sqlite3를 사용하는 Python 코드와 잘 연동됩니다.각 연산은 테이블의 행을 조작하며, WHERE 절을 사용하면 특정 레코드를 대상으로 지정할 수 있습니다.
INSERT 문은 테이블에 새 레코드를 추가합니다.파이썬에서는 `INSERT INTO Songs (title, plays) VALUES (?, ?)`와 같은 구문을 사용하여 `cursor.execute`를 호출하고 매개변수 튜플을 전달합니다. 문자열 연결 대신 플레이스홀더를 사용하면 SQL 인젝션을 방지하고 따옴표 처리를 올바르게 수행할 수 있습니다. 삽입 후에는 `conn.commit`을 호출하여 트랜잭션의 변경 사항을 데이터베이스 파일에 반영합니다.
SELECT 문은 데이터베이스에서 데이터를 읽어오며, 선택적으로 결과를 필터링하고 정렬할 수 있습니다.간단한 `SELECT title, plays FROM Songs` 쿼리는 커서를 행을 순회하는 반복 가능한 객체로 변환합니다. 결과 집합이 큰 경우 SQLite는 모든 행을 한 번에 메모리에 로드하지 않고 for 루프가 반복되는 동안 순차적으로 로드합니다. `*`를 사용하여 모든 열을 선택하거나 부분 집합을 지정할 수 있으며, `WHERE`, `ORDER BY`, `LIMIT` 절을 사용하여 레코드를 정렬하고 제한할 수 있습니다.
DELETE 문은 특정 조건에 따라 행을 영구적으로 삭제합니다.`DELETE FROM Songs WHERE plays < 100`과 같은 구문은 재생 횟수가 100 미만인 모든 노래를 삭제합니다. 실행 취소 기능이 없으므로 튜토리얼에서는 예제를 다시 실행할 때 멱등성을 확보하기 위해 스크립트 끝에서 행을 삭제하는 경우가 많습니다. 변경 사항을 저장하려면 삭제 후 반드시 커밋해야 합니다.
UPDATE는 기존 행의 열을 수정합니다.테이블, 새 값을 포함하는 SET 절, 그리고 선택적으로 WHERE 절을 지정합니다. 예를 들어, `UPDATE Songs SET plays = 16 WHERE title = 'My Way'`는 제목이 해당 문자열과 일치하는 모든 행에 영향을 미칩니다. WHERE 절을 생략하면 테이블의 모든 행이 업데이트되므로 의도치 않은 대량 변경이 발생할 수 있습니다.
SQLite와 Python을 사용하여 트위터 크롤러 구축하기
SQL과 Python을 결합한 실용적인 예시로, 상태를 SQLite 데이터베이스에 저장하는 간단한 트위터 크롤러를 들 수 있습니다.트위터의 API와 정책은 시간이 지남에 따라 변경될 수 있지만, 기본적인 아키텍처 개념은 여전히 유효합니다. 즉, 친구 관계를 탐색하고, 계정을 반복해서 방문하지 않고, 인기 지표를 수집하는 동시에 진행 상황을 잃지 않고 작업을 중단했다가 다시 시작할 수 있어야 합니다.
크롤러는 트위터 계정 목록을 테이블 형태로 유지하고 각 계정이 검색되었는지 여부와 친구로 표시된 횟수를 추적합니다.각 행에는 계정 이름, 해당 계정의 친구 목록을 이미 가져왔는지 여부를 나타내는 플래그, 그리고 해당 계정이 다른 사용자의 "친구" 목록에 나타난 횟수를 나타내는 카운터가 있습니다. 이를 통해 샘플링된 네트워크 내에서 해당 계정의 인기를 추정할 수 있습니다.
메인 루프는 사용자에게 트위터 아이디 또는 종료 명령을 입력하라는 메시지를 표시합니다.사용자가 단순히 Enter 키를 누르면 스크립트는 데이터베이스에서 복구 상태가 0인 다음 계정을 찾아 다음 대상으로 사용합니다. 그런 다음 트위터의 friends/list 엔드포인트를 호출하고 JSON 응답을 파싱하여 현재 계정의 복구 플래그를 업데이트하고 필요에 따라 각 친구 정보를 데이터베이스에 삽입하거나 업데이트하고 친구 카운터를 증가시킵니다.
모든 데이터가 SQLite에 저장되므로 크롤러를 종료했다가 나중에 다시 시작할 수 있습니다.데이터베이스는 내구성이 뛰어난 큐 및 상태 저장소 역할을 합니다. 별도의 헬퍼 스크립트를 사용하면 트위터 테이블의 내용을 덤프하여 어떤 계정을 알고 있는지, 어떤 계정을 방문했는지, 그리고 각 계정이 친구로 몇 번 나타났는지 등을 확인할 수 있습니다. 이처럼 크롤링 상태를 관계형 데이터베이스에 저장하는 방식은 다른 웹 또는 API 크롤링 작업에도 효과적으로 적용할 수 있습니다.
데이터 모델링 기초: 기본 키, 외래 키 및 정규화
트위터 정보를 모두 하나의 테이블에 저장하면 확장성과 데이터 중복 문제에 곧바로 직면하게 됩니다.보다 견고한 접근 방식은 개체(사람)와 관계(누가 누구를 따르는지)를 분리하고 키를 통해 연결하여 데이터를 정규화하는 것입니다.
일반적으로 사용자 테이블은 내부 식별자로 정수형 기본 키를 사용합니다.SQLite에서는 `id INTEGER PRIMARY KEY`로 선언하면 SQLite 엔진이 삽입되는 각 행에 대해 고유한 정수 값을 자동으로 생성합니다. 또한 중복을 방지하기 위해 트위터 핸들과 같은 논리 키를 `UNIQUE`로 지정하여 포함합니다. 논리 키는 외부에서 사용하는 키이고, 기본 키는 코드와 외래 키가 참조하는 키입니다.
별도의 팔로우 테이블에서 외래 키를 사용하여 관계를 기록합니다.각 행에는 일반적으로 from_id와 to_id(또는 이와 유사한 이름)로 명명된 사용자 ID 쌍이 포함되어 있으며, 이는 한 사람이 다른 사람을 팔로우한다는 것을 나타냅니다. 이 두 열의 조합에 UNIQUE 제약 조건을 선언하면 동일한 관계가 실수로 두 번 삽입되는 것을 방지할 수 있습니다.
정규화는 각 정보를 한 번만 저장하고 키를 사용하여 다른 곳에서 참조하는 방식으로, 중복을 방지하고 공간을 절약하며 성능을 향상시킵니다.수백만 개의 관계 행에 동일한 사용자 이름 문자열을 저장하는 대신, 사람 테이블에 한 번만 저장하고 정수 ID를 통해 참조합니다. 정수는 비교 및 인덱싱 속도가 빠르므로 규모가 커질수록 매우 중요해집니다.
파이썬 코드에서 이러한 설계는 사용자와 관계를 삽입하거나 검색하는 데 있어 공통적인 패턴으로 이어집니다.관계를 삽입하기 전에 두 참여자가 모두 사람 테이블에 존재하는지 확인해야 합니다. 논리적 키를 사용하여 SELECT 쿼리를 실행하고, 행이 없으면 INSERT 쿼리를 실행하여 마지막 행 ID를 새 참여자의 ID로 저장합니다. 그런 다음 해당 ID를 연결하는 행을 다음 테이블에 INSERT 또는 IGNORE 쿼리를 사용하여 추가합니다. 제약 조건과 OR IGNORE 쿼리를 함께 사용하면 과도한 수동 검사 없이도 데이터의 일관성을 유지할 수 있습니다.
SQL에서 JOIN을 사용하여 관련 테이블을 결합합니다.
데이터가 여러 개의 정규화된 테이블에 분산되어 있는 경우, 필요한 결합 뷰를 재구성하기 위해 SQL JOIN을 사용해야 합니다.JOIN은 키 값이 일치하는 두 테이블의 행을 병합하여, 각 일치 항목에 대해 사실상 하나의 넓은 행을 생성합니다.
트위터 예시에서, 팔로우 테이블과 팔로워 테이블을 결합하면 특정 사용자가 누구를 팔로우하는지 또는 누가 그 사용자를 팔로우하는지 확인할 수 있습니다.예를 들어 `SELECT * FROM Follow JOIN People ON Follow.to_id = People.id WHERE Follow.from_id = 2`와 같은 쿼리는 내부 ID가 2인 사용자가 팔로우하는 모든 사람을 검색합니다. `JOIN` 절은 데이터베이스에 각 행에 대해 `Follow.to_id`와 `People.id`를 일치시키도록 지시하고, `WHERE` 조건은 소스 사용자를 제한합니다.
결과 집합에는 두 테이블의 열이 모두 포함됩니다.팔로우 테이블의 두 개의 정수 ID 다음에 사용자 테이블의 전체 사용자 정보(ID, 핸들, 복구 플래그)가 표시될 수 있습니다. 사용자가 여러 계정을 팔로우하는 경우, 관계별로 하나의 통합 행이 생성되어 원본 사용자의 일부 열이 중복되지만 대상 사용자의 속성에 쉽게 접근할 수 있습니다.
JOIN에는 INNER, LEFT, RIGHT, FULL 등 여러 종류가 있지만, 일반적인 설계에서는 핵심 관계에 INNER JOIN을 사용하는 것이 일반적입니다.INNER JOIN은 양쪽에 일치하는 행만 유지하는데, 이는 관계 행이 항상 기존 인물을 참조해야 한다는 개념과 일치합니다. 디버깅이나 탐색 시 각 테이블과 JOIN 쿼리에서 몇 개의 행을 선택하여 모델이 예상대로 작동하는지 확인할 수 있습니다.
이러한 관계 패턴은 사용자와 역할, 고객과 주문, 제품과 카테고리, 게시물과 댓글 등 모든 곳에서 나타납니다.기본 키와 외래 키를 사용하여 테이블을 설계하고 JOIN 쿼리를 작성하는 데 익숙해지면, 파이썬의 고급 논리 및 분석 기능을 활용하여 복잡한 도메인을 모델링하고 쿼리할 수 있습니다.
종합적으로 말하자면, SQL과 Python을 마스터한다는 것은 깔끔한 쿼리나 스크립트를 작성하는 방법뿐만 아니라 런타임, 드라이버, 데이터 유형 및 리소스 제한이 플랫폼 전반에 걸쳐 어떻게 상호 작용하는지 이해하는 것을 의미합니다.SQL Server에서 발생하는 복잡한 머신 러닝 서비스 오류를 진단하고 샌드박스 환경에서 Python 라이브러리 종속성을 관리하는 것부터 정규화된 SQLite 스키마를 설계하고 엔드투엔드 분석 파이프라인을 구성하는 것까지, 데이터베이스와 코드 사이를 유연하게 오갈수록 데이터 솔루션은 더욱 견고하고 확장 가능해집니다.