2011-01-03 55 views
5

Hãy tưởng tượng một bảng với cấu trúc sau đây trên PostgreSQL 9.0:PostgreSQL: Đang tải dữ liệu vào sao Schema hiệu quả

create table raw_fact_table (text varchar(1000)); 

Vì lợi ích của việc đơn giản hóa tôi chỉ đề cập đến một cột văn bản, trên thực tế nó có một chục. Bảng này có 10 tỷ hàng và mỗi cột có nhiều bản sao. Bảng được tạo từ một tệp phẳng (csv) bằng COPY FROM.

Để tăng hiệu suất Tôi muốn chuyển đổi cơ cấu schema sao sau:

create table dimension_table (id int, text varchar(1000)); 

Bảng thực tế sau đó sẽ được thay thế bằng một bảng thực tế như sau:

create table fact_table (dimension_table_id int); 

phương pháp hiện tại của tôi về cơ bản sẽ chạy truy vấn sau để tạo bảng thứ nguyên:

Create table dimension_table (id int, text varchar(1000), primary key(id)); 

sau đó để tạo điền vào bảng chiều tôi sử dụng:

insert into dimension_table (select null, text from raw_fact_table group by text); 

Sau đó tôi cần phải chạy truy vấn sau đây:

select id into fact_table from dimension inner join raw_fact_table on (dimension.text = raw_fact_table.text); 

Chỉ cần tưởng tượng hiệu suất khủng khiếp tôi nhận được bằng cách so sánh tất cả các chuỗi để tất cả các chuỗi khác nhiều lần.

Trên MySQL, tôi có thể chạy thủ tục được lưu trữ trong COPY FROM. Điều này có thể tạo ra một băm của một chuỗi và tất cả so sánh chuỗi tiếp theo được thực hiện trên băm thay vì chuỗi thô dài. Điều này dường như không thể thực hiện được trên PostgreSQL, tôi phải làm gì sau đó?

dữ liệu mẫu sẽ là một tập tin CSV có chứa một cái gì đó như thế này (tôi sử dụng dấu ngoặc kép cũng xung quanh số nguyên và tăng gấp đôi):

"lots and lots of text";"3";"1";"2.4";"lots of text";"blabla" 
"sometext";"30";"10";"1.0";"lots of text";"blabla" 
"somemoretext";"30";"10";"1.0";"lots of text";"fooooooo" 
+0

Thời gian này có vẻ như thế nào? Bạn mong đợi nó mất bao lâu? –

+0

Tôi chưa bao giờ hoàn thành nó bằng số lượng dữ liệu được đề cập. Nhưng trên 15 triệu hàng phải mất vài giờ. Tôi đã xem xét tất cả các công cụ tối ưu hóa máy chủ tiêu chuẩn (work_mem, vv) vì vậy tôi sau khi một phương pháp khác nhau để đạt được kết quả tương tự. – David

+0

Đăng dữ liệu mẫu và DDL. –

Trả lời

2

Chỉ cần đặt câu hỏi: - cần chuyển đổi dữ liệu của bạn theo 1 hoặc 2 bước? - Chúng tôi có thể sửa đổi bảng trong khi chuyển đổi không?

Chạy truy vấn đơn giản hơn nhiều có thể cải thiện hiệu suất của bạn (và tải máy chủ trong khi làm việc đó)

Một cách tiếp cận sẽ là:

  1. tạo dimension_table (Nếu tôi hiểu nó một cách chính xác, bạn không có vấn đề hiệu năng với điều này) (có thể với trường boolean bổ sung tạm thời ...)
  2. lặp lại: chọn một mục nhập trước đó không được chọn từ dimension_table, chọn mọi hàng từ raw_fact_table có chứa nó và chèn chúng vào fact_table. Đánh dấu kỷ lục dimension_table as done, và tiếp theo ... Bạn có thể viết những dòng này như một thủ tục lưu trữ, và nó có thể chuyển đổi dữ liệu của bạn ở chế độ nền, ăn nguồn lực tối thiểu ...

Hoặc khác (có thể là tốt hơn):

  1. tạo fact_table làm MỌI bản ghi từ raw_fact_table VÀ một dimension_id.(Do đó bao gồm dimension_text và hàng dimension_id)
  2. tạo dimension_table
  3. tạo sau khi chèn kích hoạt cho fact_table đó:
    • tìm kiếm dimension_text trong fact_table
    • nếu không tìm thấy, tạo ra một kỷ lục mới trong dimension_table
    • cập nhật dimension_id vào id này
  4. theo vòng lặp simle, chèn mọi bản ghi từ raw_fact_table vào fact_table
+0

Cảm ơn bạn đã đề xuất. Tôi không chỉ rõ điều này, nhưng mối quan tâm duy nhất của tôi là xử lý tất cả dữ liệu nhanh nhất có thể, vì vậy chạy một thứ gì đó trong nền không tạo ra sence trong thiết lập của tôi (tôi biết nó rất khôn ngoan trong các tình huống khác). Vấn đề với cách tiếp cận thứ hai của bạn là các trigger không được kích hoạt trên COPY FROM. Vì vậy, tôi tin rằng không có lý do gì để kích hoạt. Cách tiếp cận của bạn mặc dù vẫn còn rất nhiều giá trị sử dụng một con trỏ. Mặc dù tôi không chắc chắn về hiệu suất: http://stackoverflow.com/questions/4776127/postgres-surprising-performance-on-updates-using-cursor – David

+0

Liên quan đến cách tiếp cận đầu tiên của bạn, tôi chưa hẹn giờ hiệu suất của quá trình tạo bảng kích thước (tôi nên làm điều này). Tôi thích cách tiếp cận của bạn với suy nghĩ theo cách khác xung quanh. Tôi sẽ tạo một bình luận mới với một cách tiếp cận dựa trên ý kiến ​​của bạn. – David

+0

tạo bảng dimension_table (id nối tiếp, văn bản varchar (1000), raw_fact_table_id bigint [], khóa chính (id)); ------------------- chèn vào dimension_table (văn bản , raw_fact_table_id) (chọn văn bản, array_agg (raw_fact_table.id) từ nhóm raw_fact_table bằng văn bản); sau đó người ta sẽ cần phải tìm cách cập nhật raw_fact_table dựa trên các id trong raw_fact_table_id. Bạn nghĩ sao? – David

2

Bạn đang bỏ qua một số chi tiết có lúc kết thúc, nhưng tôi không thấy rằng có nhất thiết là một vấn đề. Nó không phải là bằng chứng cho thấy tất cả các chuỗi thực sự được so sánh với tất cả các chuỗi khác. Nếu bạn tham gia, PostgreSQL có thể chọn một thuật toán tham gia thông minh hơn, chẳng hạn như tham gia băm, có thể cung cấp cho bạn cùng một băm mà bạn đang tự triển khai trong giải pháp MySQL của mình. (Một lần nữa, thông tin của bạn đang mơ hồ về điều đó.)

+0

Cảm ơn câu trả lời của bạn. Tôi đã cập nhật câu hỏi ngay bây giờ, với các chi tiết còn thiếu. – David

6

Chỉ cần tưởng tượng hiệu suất khủng khiếp tôi nhận được bằng cách so sánh tất cả các chuỗi cho tất cả chuỗi khác nhiều lần.

Khi bạn đã thực hiện việc này một lúc, bạn dừng tưởng tượng hiệu suất và bắt đầu đo. "Tối ưu hóa sớm là gốc rễ của mọi điều ác".

"Tỷ" có ý nghĩa gì đối với bạn? Với tôi, ở Mỹ, nó có nghĩa là 1.000.000.000 (hoặc 1e9). Nếu điều đó cũng đúng đối với bạn, có thể bạn đang xem từ 1 đến 7 terabyte dữ liệu.

phương pháp hiện tại của tôi là về cơ bản chạy truy vấn sau đây để tạo ra các bảng chiều:

Create table dimension_table (id int, text varchar(1000), primary key(id)); 

How are you sẽ phù hợp với 10 tỷ hàng vào một bảng có sử dụng một số nguyên cho một khóa chính? Thậm chí hãy nói rằng một nửa số hàng là trùng lặp. Làm thế nào mà số học làm việc khi bạn làm điều đó?

Đừng tưởng tượng. Đọc trước. Sau đó kiểm tra.

Đọc Data Warehousing with PostgreSQL. Tôi nghi ngờ các trang trình bày này sẽ cung cấp cho bạn một số ý tưởng.

Đồng thời đọc Populating a Database và xem xét các đề xuất cần triển khai.

Kiểm tra với hàng triệu (1e6) hàng, theo quy trình "chia và chinh phục". Đó là, đừng cố gắng tải một triệu tại một thời điểm; viết một thủ tục phá vỡ nó thành những phần nhỏ hơn. Chạy

EXPLAIN <sql statement> 

Bạn đã nói bạn ước tính ít nhất 99% hàng trùng lặp. Nói chung, có hai cách để loại bỏ các hình ảnh hai chiều

  1. Bên trong cơ sở dữ liệu, không nhất thiết phải là nền tảng bạn sử dụng cho sản xuất.
  2. Ngoài cơ sở dữ liệu, trong hệ thống tệp, không nhất thiết phải là hệ thống tệp tương tự mà bạn sử dụng để sản xuất.

Nếu bạn vẫn có tệp văn bản bạn đã tải, trước tiên tôi sẽ xem xét thử bên ngoài cơ sở dữ liệu. Điều này một chiều lót sẽ xuất ra dòng duy nhất từ ​​mỗi tập tin. Đó là tương đối kinh tế, trong đó nó làm cho chỉ có một vượt qua các dữ liệu.

awk '!arr[$0]++' file_with_dupes > file_without_dupes 

Nếu bạn thực sự có 99% giá trị nhân bản, vào cuối của quá trình này bạn nên đã làm giảm của bạn 1-7 terabyte xuống khoảng 50 hợp đồng biểu diễn. Và, khi thực hiện điều đó, bạn cũng có thể đánh số từng dòng duy nhất và tạo một tệp được phân cách bằng tab trước khi sao chép nó vào kho dữ liệu. Đó là một one-liner:

awk '{printf("%d\t%s\n", NR, $0);}' file_without_dupes > tab_delimited_file 

Nếu bạn phải làm điều này trong môi trường Windows, tôi muốn sử dụng Cygwin.

Nếu bạn phải làm điều này trong cơ sở dữ liệu, tôi sẽ cố gắng tránh sử dụng cơ sở dữ liệu sản xuất hoặc máy chủ sản xuất của bạn. Nhưng có lẽ tôi quá thận trọng. Di chuyển một vài terabyte xung quanh là một điều đắt tiền để làm.

Nhưng tôi muốn thử nghiệm

SELECT DISTINCT ... 

trước khi sử dụng GROUP BY. Tôi có thể làm một số bài kiểm tra trên một tập dữ liệu lớn cho bạn, nhưng có lẽ không phải trong tuần này. (Tôi không thường làm việc với các tập tin có kích cỡ terabyte. Thật thú vị. Nếu bạn có thể chờ đợi.)

+0

Tôi đang nhận được hiệu suất khủng khiếp và tôi yêu cầu tư vấn cụ thể để giải quyết vấn đề cụ thể. Raw_fact_table không có số nguyên cho khóa chính. Chỉ các bảng thứ nguyên có 99.XX% bản sao trong fact_table. Tôi đã thực hiện tất cả lời khuyên từ các liên kết bạn đã gửi cho tôi. – David

+0

Chữ "T" trong "ETL" đang giết bạn. 99% bản sao có nghĩa là bạn đang nhắm đến khoảng 100.000.000 hàng. Tôi sẽ chỉnh sửa câu trả lời của mình. –

+0

Để đơn giản hóa ví dụ, tôi chỉ đề cập rằng raw_fact_table có một cột văn bản. Trong thực tế nó có một tá, do đó, phương pháp của bạn để loại bỏ các bản sao sẽ không làm việc, cảm ơn cho chỉ ra điều này, mặc dù. Tôi sẽ cập nhật câu hỏi. Raw_fact_table cũng có giá trị số nguyên và giá trị kép. – David

1

tôi một thấy một số cách để giải quyết vấn đề của bạn Có chức năng md5 trong PostgreSQL md5 (string) Tính băm MD5 của chuỗi, trở về kết quả trong hệ thập lục phân

chèn vào dimension_table (chọn null, md5 (văn bản), văn bản từ nhóm raw_fact_table theo văn bản)

thêm trường md5 vào raw_fact_table cũng như chọn id vào fact_table từ tham số bên trong tham gia raw_fact_table trên (dimension.md5 = raw_fact_table.md5);

Chỉ mục trên MD5 được gửi cũng có thể giúp đỡ

Hoặc bạn có thể tính toán MD5 khi đang tải dữ liệu. Ví dụ: công cụ ETL Bộ xử lý ETL nâng cao của chúng tôi có thể làm điều đó cho bạn. Plus nó có thể tải dữ liệu vào nhiều bảng cùng một lúc.

Có một số hướng dẫn trên mạng có sẵn trên trang web của chúng tôi Ví dụ này cho thấy tải thay đổi chiều hướng chậm

http://www.dbsoftlab.com/online-tutorials/advanced-etl-processor/advanced-etl-processor-working-with-slow-changing-dimension-part-2.html

+0

Tôi không tin ai có thể chạy tính toán MD5 khi chạy COPY FROM (đây là cách được khuyến nghị để tải dữ liệu). Nếu điều này có nghĩa là công cụ của bạn không sử dụng COPY FROM, thì tôi tin rằng nó vô dụng khi tải mà không có điều này sẽ mất nhiều thời gian. Tôi phải nói rằng tôi rất hoài nghi về giải pháp ETL ít mã. Nó miễn là tôi chỉ cần làm công cụ chuẩn, nhưng nếu tôi từng gặp vấn đề đặc biệt, tôi không có mã nào để quay lại. – David

+0

Hoàn toàn đồng ý với bạn COPY FROM là cách nhanh nhất để tải dữ liệu vào PostgreSQL. Đây là lý do tại sao chúng tôi sử dụng nó trong bộ xử lý ETL nâng cao. Từ tài liệu PostgreSQL: COPY TABLE_NAME TỪ STDIN (STDIN Chỉ định đầu vào đến từ ứng dụng khách.) –

+0

Chúng tôi đã cố gắng hết sức để làm cho nó càng nhanh càng tốt. Đối với mọi cơ sở dữ liệu, chúng tôi sử dụng cách tải dữ liệu nhanh chóng. (Đường dẫn trực tiếp/thông thường cho oracle, bcp cho SQL Server, sao chép từ cho PostgreSQL, vv) Chúng tôi đã in mã quan trọng và đánh dấu và loại bỏ tất cả các phần không hiệu quả. Hơn chúng tôi sử dụng hiệu suất profiler và tối ưu hơn nữa. Chúng tôi liên tục cải tiến. (Hãy xem diễn đàn hỗ trợ của chúng tôi và lưu ý mất bao lâu để giải quyết vấn đề hoặc giới thiệu tính năng mới hơn so sánh nó với người chơi lớn). –

2
-- add unique index 
CREATE UNIQUE INDEX uidx ON dimension_table USING hash(text); 
-- for non case-sensitive hash(upper(text)) 

thử băm (văn bản); và btree (văn bản) để xem cái nào nhanh hơn

Các vấn đề liên quan