Những ưu và nhược điểm của việc thực hiện tính toán trong sql so với trong ứng dụng của bạn là gì


154

shopkeeper bảng có các trường sau:

id (bigint),amount (numeric(19,2)),createddate (timestamp)

Hãy nói rằng, tôi có bảng trên. Tôi muốn lấy hồ sơ cho ngày hôm qua và tạo một báo cáo bằng cách in số tiền ra xu.

Một cách làm là thực hiện các phép tính trong ứng dụng java của tôi và thực hiện một truy vấn đơn giản

Date previousDate ;// $1 calculate in application

Date todayDate;// $2 calculate in application

select amount where createddate between $1 and $2 

và sau đó lặp qua các bản ghi và chuyển đổi số tiền thành xu trong ứng dụng java của tôi và tạo báo cáo

Một cách khác giống như thực hiện các phép tính trong chính truy vấn sql:

select cast(amount * 100 as int) as "Cents"
from shopkeeper  where createddate  between date_trunc('day', now()) - interval '1 day'  and  date_trunc('day', now())

và sau đó lặp qua các bản ghi và tạo báo cáo

Theo một cách nào đó, tất cả quá trình xử lý của tôi được thực hiện trong ứng dụng java và một truy vấn đơn giản được thực hiện. Trong trường hợp khác, tất cả các chuyển đổi và tính toán được thực hiện trong truy vấn Sql.

Trường hợp sử dụng ở trên chỉ là một ví dụ, trong một kịch bản thực, một bảng có thể có nhiều cột yêu cầu xử lý loại tương tự.

Bạn có thể vui lòng cho tôi biết cách tiếp cận nào tốt hơn về mặt hiệu suất và các khía cạnh khác và tại sao?


2
Các tính toán ngày sẽ có ít hoặc không ảnh hưởng gì cả - giả sử công cụ sql của bạn thực sự sẽ chỉ tính ngày của bạn một lần. để chúng được xác định trong ứng dụng của bạn có ý nghĩa hoàn hảo, vì dù sao chúng sẽ được xác định ở đó vào một lúc nào đó, có thể là tiêu đề báo cáo hoặc những thứ khác. nhân giá trị với 100 trong trường hợp này có thể được thực hiện trên bất kỳ tầng nào, vì dù sao bạn cũng sẽ lặp qua các hàng đó để hiển thị và * 100 không thể chậm hơn trên bất kỳ tầng nào ngoại trừ giao diện người dùng. Trong cả hai trường hợp, tính toán của bạn là tối thiểu và bị lấn át bởi các hoạt động xung quanh, không phải là vấn đề hiệu suất.
Mẹ ơi.

Câu trả lời:


206

Nó phụ thuộc vào rất nhiều yếu tố - nhưng chủ yếu là:

  • độ phức tạp của các phép tính (thích thực hiện crunching phức tạp trên một máy chủ ứng dụng, vì nó mở rộng ra ; thay vì một máy chủ db, mở rộng ra )
  • khối lượng dữ liệu (nếu bạn cần truy cập / tổng hợp nhiều dữ liệu, thực hiện tại máy chủ db sẽ tiết kiệm băng thông và đĩa io nếu việc tổng hợp có thể được thực hiện trong các chỉ mục)
  • tiện lợi (sql không phải là ngôn ngữ tốt nhất cho công việc phức tạp - đặc biệt không tuyệt vời cho công việc thủ tục, nhưng rất tốt cho công việc dựa trên tập hợp; mặc dù xử lý lỗi tệ hại)

Như mọi khi, nếu bạn làm mang lại dữ liệu vào ứng dụng máy chủ, giảm thiểu các cột và các hàng sẽ là lợi thế của bạn. Đảm bảo truy vấn được điều chỉnh và lập chỉ mục phù hợp sẽ giúp cả hai kịch bản.

Lưu ý của bạn:

và sau đó lặp qua các bản ghi

Vòng lặp thông qua các bản ghi hầu như luôn luôn là điều sai trong sql - viết một hoạt động dựa trên tập hợp được ưa thích.

Theo nguyên tắc chung , tôi thích giữ công việc của cơ sở dữ liệu ở mức tối thiểu "lưu trữ dữ liệu này, tìm nạp dữ liệu này" - tuy nhiên, luôn có các ví dụ về các tình huống trong đó một truy vấn thanh lịch tại máy chủ có thể tiết kiệm rất nhiều băng thông.

Cũng xem xét: nếu điều này là tính toán đắt tiền, nó có thể được lưu trữ ở đâu đó không?

Nếu bạn muốn một " chính xác hơn"; mã cả hai cách và so sánh nó (lưu ý rằng bản nháp đầu tiên của một trong hai có khả năng không được điều chỉnh 100%). Nhưng yếu tố sử dụng điển hình cho điều đó: nếu trong thực tế, nó được gọi 5 lần (riêng biệt) cùng một lúc, sau đó mô phỏng rằng: đừng so sánh chỉ một "1 trong số này với 1 trong số đó".


Vòng lặp ngụ ý quá trình xử lý "hàng tại một thời điểm" ít nhiều. Và điều đó có nghĩa là độ trễ mạng 2 * cộng với bốn chuyển mạch bối cảnh. Vâng: đó là đắt tiền. Hoạt động DBMS "bản địa" thực hiện tất cả công việc khó khăn để giảm thiểu các I / O của đĩa (gọi hệ thống) nhưng quản lý để tìm nạp nhiều hơn một hàng trên mỗi lệnh gọi hệ thống. Hàng tại một thời điểm mất ít nhất bốn cuộc gọi hệ thống.
wildplasser

@wildplasser không cần thiết; máy chủ có thể phát trực tuyến các hàng mà bạn tiêu thụ khi chúng đến - một phép ẩn dụ "người đọc" không phải là hiếm.
Marc Gravell

1
@Marc Cavell: Vâng, nó phụ thuộc. Trong trường hợp dấu chân của một chương trình ứng dụng chỉ là một bản ghi logic, thì ít nhiều Ok. Nhưng hầu hết các "khung" mà tôi biết có xu hướng hút tất cả các hồ sơ khi khởi động, và loại bỏ chúng từng cái một. Khóa là một cạm bẫy khác.
wildplasser

Tôi nghĩ rằng một nguyên tắc nhỏ là: không mang về từ các hàng dữ liệu của máy chủ SQL mà cuối cùng bạn không cần. Ví dụ: nếu bạn phải thực hiện các thao tác tổng hợp, chúng có thể thuộc về SQL. Tham gia giữa các bảng hoặc truy vấn con? SQL. Đó cũng là cách tiếp cận chúng tôi sử dụng với huy hiệu, và cho đến nay, chúng tôi đang đối phó với quy mô :-)
Sklivvz

1
@zinking đó sẽ là một hoạt động dựa trên thiết lập. Trong kịch bản đó, bạn không viết mã vòng lặp - đó là một chi tiết triển khai. Bằng cách "lặp" tôi có nghĩa là các vòng lặp rõ ràng, ví dụ như một con trỏ
Marc Gravell

86

Hãy để tôi sử dụng một phép ẩn dụ: nếu bạn muốn mua một sợi dây chuyền vàng ở Paris, thợ kim hoàn có thể ngồi ở Cape Town hoặc Paris, đó là một vấn đề về kỹ năng và hương vị. Nhưng bạn sẽ không bao giờ vận chuyển hàng tấn quặng vàng từ Nam Phi đến Pháp cho điều đó. Quặng được xử lý tại khu vực khai thác (hoặc ít nhất là trong khu vực chung), chỉ có vàng được vận chuyển. Điều này cũng đúng với các ứng dụng và cơ sở dữ liệu.

Theo như PostgreSQL , bạn có thể làm hầu hết mọi thứ trên máy chủ, khá hiệu quả. RDBMS vượt trội tại các truy vấn phức tạp. Đối với các nhu cầu về thủ tục, bạn có thể chọn từ nhiều ngôn ngữ kịch bản phía máy chủ : tcl, python, perl và nhiều ngôn ngữ khác. Hầu hết tôi sử dụng PL / pgSQL .

Trường hợp xấu nhất sẽ là liên tục đến máy chủ cho mỗi hàng của một bộ lớn hơn. (Điều đó sẽ giống như vận chuyển một tấn quặng một lần.)

Dòng thứ hai , nếu bạn gửi một loạt các truy vấn, mỗi tùy thuộc vào một truy vấn trước đó, trong khi tất cả các truy vấn có thể được thực hiện trong một truy vấn hoặc thủ tục trên máy chủ. (Điều đó giống như vận chuyển vàng và mỗi viên ngọc với một con tàu riêng biệt, theo trình tự.)

Quay trở lại giữa ứng dụng và máy chủ là tốn kém. Đối với máy chủ máy khách. Cố gắng cắt giảm điều đó và bạn sẽ giành chiến thắng - ergo: sử dụng các quy trình phía máy chủ và / hoặc SQL tinh vi khi cần thiết.

Chúng tôi vừa hoàn thành một dự án nơi chúng tôi đóng gói gần như tất cả các truy vấn phức tạp vào các hàm Postgres. Ứng dụng bàn giao các tham số và lấy bộ dữ liệu cần thiết. Nhanh chóng, sạch sẽ, đơn giản (đối với nhà phát triển ứng dụng), I / O giảm đến mức tối thiểu ... một vòng cổ sáng bóng với dấu chân carbon thấp.


12
Tôi thận trọng về việc sử dụng sự tương tự này để đưa ra quyết định thiết kế có ý nghĩa với các nhà phát triển khác. Tương tự là một thiết bị hùng biện hơn là một thiết bị hợp lý. Trong số các yếu tố khác, việc gửi dữ liệu đến máy chủ ứng dụng rẻ hơn rất nhiều so với việc vận chuyển quặng vàng cho thợ kim hoàn.
Doug

3
Bạn sẽ gửi quặng hoặc vàng tùy theo giá rẻ hơn, nếu bạn không có công nghệ chuyển đổi quặng thành vàng hoặc đắt tiền (vì các công ty khai thác muốn giết những công nhân khác này), bạn sẽ chuyển nó đến một địa điểm khác, có thể trong giữa thợ kim hoàn và thợ mỏ, đặc biệt nếu bạn có nhiều hơn một thợ kim hoàn.
Dainius

1
chính xác những gì tôi đồng ý, tôi không nghĩ việc tính toán dựa trên vòng lặp trong SQL @a_horse_with_no_name luôn là điều tồi tệ, đôi khi điều này phải được thực hiện bằng mọi cách, tôi thà tính toán khi dữ liệu được lấy theo ẩn dụ của Erwin. hoặc bạn phải lặp lại điều này với chi phí khi dữ liệu được tải lại.
zinking

-1 Bởi vì đó là một cuộc tranh cãi một chiều, bỏ qua sự đánh đổi và thiết lập một người rơm cho phe đối lập thay vì xem xét và bác bỏ trường hợp tốt nhất của phe đối lập. "Quay đi quay lại giữa ứng dụng và máy chủ rất tốn kém" - hoàn toàn: nhưng đó không phải là điều duy nhất đắt đỏ và các chi phí khác nhau phải được cân nhắc với nhau. Nó có thể chỉ ra rằng các truy vấn "SQL tinh vi" hoặc các thủ tục được lưu trữ là tốt nhất cho trường hợp cụ thể; nhưng các chi tiết của vụ án thường phải được tính đến khi đưa ra quyết định đó.
yfeldblum

Tương tự tuyệt vời nhưng thật không may, nó dựa trên các giả định sai. Vận chuyển quặng vàng rất phổ biến. Tỷ lệ tước vàng là khoảng 1: 1 (vàng thành chất thải) tuy nhiên thường rẻ hơn khi xử lý ngoài cơ sở, nơi có thiết bị tốt hơn và chất lượng tay nghề cao hơn. Tùy thuộc vào kích thước của lô hàng, tăng 0,1% hiệu quả xử lý có thể cho phép tăng doanh thu tương đối (mặc dù giá vận chuyển tăng gấp đôi) - vì vàng ngày nay khá đắt. Các quặng khác, chẳng hạn như sắt thường được vận chuyển (tỷ lệ tước của sắt là khoảng 60%!).
Chris Koston

18

Trong trường hợp này, bạn có thể tốt hơn một chút khi thực hiện phép tính trong SQL vì công cụ cơ sở dữ liệu có thể có các thói quen số học thập phân hiệu quả hơn so với Java.

Nói chung mặc dù đối với tính toán mức hàng không có nhiều khác biệt.

Nơi mà nó làm cho một sự khác biệt là:

  • Các phép tính tổng hợp như SUM (), AVG (), MIN (), MAX () ở đây, công cụ cơ sở dữ liệu sẽ có thứ tự nhanh hơn so với triển khai Java.
  • Bất cứ nơi nào tính toán được sử dụng để lọc hàng. Lọc tại DB hiệu quả hơn nhiều so với đọc một hàng và sau đó loại bỏ nó.

12

Không có màu đen / trắng đối với phần nào của logic truy cập dữ liệu nên được thực hiện trong SQL và phần nào nên được thực hiện trong ứng dụng của bạn. Tôi thích từ ngữ của Mark Gravell , phân biệt giữa

  • tính toán phức tạp
  • tính toán chuyên sâu dữ liệu

Sức mạnh và tính biểu cảm của SQL bị đánh giá thấp. Kể từ khi giới thiệu các chức năng của cửa sổ , rất nhiều tính toán định hướng không nghiêm ngặt có thể được thực hiện rất dễ dàng và thanh lịch trong cơ sở dữ liệu.

Ba quy tắc ngón tay cái phải luôn được tuân theo, bất kể kiến ​​trúc ứng dụng tổng thể:

  • giữ cho lượng dữ liệu được chuyển giữa cơ sở dữ liệu và ứng dụng mỏng (có lợi cho việc tính toán công cụ trong DB)
  • giữ cho lượng dữ liệu được tải từ đĩa bằng cơ sở dữ liệu mỏng (có lợi cho phép cơ sở dữ liệu tối ưu hóa các câu lệnh để tránh truy cập dữ liệu không cần thiết)
  • không đẩy cơ sở dữ liệu đến giới hạn CPU của nó bằng các phép tính phức tạp, đồng thời (có lợi cho việc kéo dữ liệu vào bộ nhớ ứng dụng và thực hiện các phép tính ở đó)

Theo kinh nghiệm của tôi, với một DBA đàng hoàng và một số kiến ​​thức tốt về cơ sở dữ liệu phong nha của bạn, bạn sẽ không gặp phải giới hạn CPU DB của mình.

Một số đọc thêm trong đó những điều này được giải thích:


2

Nói chung, hãy làm mọi thứ trong SQL nếu có các mô-đun hoặc thành phần khác trong cùng hoặc các dự án khác sẽ cần để có được các kết quả đó. một hoạt động nguyên tử được thực hiện phía máy chủ cũng tốt hơn bởi vì bạn chỉ cần gọi Proc được lưu trữ từ bất kỳ công cụ quản lý db nào để có được các giá trị cuối cùng mà không cần xử lý thêm.

Trong một số trường hợp, điều này không áp dụng nhưng khi nó có ý nghĩa. nói chung, hộp db có phần cứng và hiệu suất tốt nhất.


Khả năng sử dụng lại có thể có mặt ở bất kỳ tầng nào và không phải là lý do (hiệu suất khôn ngoan) để đặt nhiều phép tính hơn trong SQL. "Nói chung hộp db": điều này là sai và hơn nữa, như marc gravell đã nói, tỷ lệ không hoạt động theo cùng một kiểu. Hầu hết các cơ sở dữ liệu yêu cầu ít phần cứng để chạy ổn định và mẫu hiệu suất ít liên quan đến máy chủ ứng dụng (ví dụ: tôi dành 2/3 ngân sách của mình cho máy chủ SQL cho IO thần thánh trong khi tôi sẽ không chi nhiều hơn hơn một vài trăm cho ngăn xếp lưu trữ của máy chủ ứng dụng).
Mẹ ơi.

1

Nếu bạn đang viết trên ORM hoặc viết các ứng dụng hiệu suất thấp thông thường, hãy sử dụng bất kỳ mẫu nào đơn giản hóa ứng dụng. Nếu bạn đang viết một ứng dụng hiệu suất cao và suy nghĩ cẩn thận về quy mô, bạn sẽ giành chiến thắng bằng cách chuyển xử lý sang dữ liệu. Tôi mạnh mẽ ủng hộ việc di chuyển xử lý dữ liệu.

Hãy suy nghĩ về điều này theo hai bước: (1) giao dịch OLTP (số lượng bản ghi nhỏ). (2) OLAP (quét dài nhiều hồ sơ).

Trong trường hợp OLTP, nếu bạn muốn nhanh chóng (10k - 100k giao dịch mỗi giây), bạn phải xóa chốt, khóa và tranh chấp khóa chết khỏi cơ sở dữ liệu. Điều này có nghĩa là bạn cần loại bỏ các gian hàng dài trong các giao dịch: các chuyến đi khứ hồi từ máy khách đến DB để chuyển xử lý sang máy khách là một trong những gian hàng dài như vậy. Bạn không thể có các giao dịch tồn tại lâu dài (để thực hiện đọc / cập nhật nguyên tử) và có thông lượng rất cao.

Re: tỉ lệ ngang. Cơ sở dữ liệu hiện đại quy mô theo chiều ngang. Những hệ thống này thực hiện HA và khả năng chịu lỗi. Tận dụng điều đó và cố gắng đơn giản hóa không gian ứng dụng của bạn.

Chúng ta hãy xem OLAP - trong trường hợp này, rõ ràng việc kéo dữ liệu có thể trở lại vào ứng dụng là một ý tưởng khủng khiếp. Các hệ thống này được xây dựng đặc biệt để hoạt động cực kỳ hiệu quả đối với dữ liệu cột được nén, được tổ chức trước. Các hệ thống OLAP hiện đại cũng mở rộng quy mô theo chiều ngang và có các nhà hoạch định truy vấn tinh vi phân tán công việc theo chiều ngang (di chuyển nội bộ xử lý dữ liệu).


0

Việc thực hiện tính toán ở mặt trước hay ở phần phụ trợ được quyết định rất nhiều nếu chúng ta có thể xác định mục tiêu của mình trong quá trình thực hiện kinh doanh. Tại thời điểm mã java có thể hoạt động tốt hơn mã sql cả bằng văn bản hoặc nó có thể ngược lại. Nhưng nếu vẫn còn bối rối, bạn có thể thử xác định trước -

  1. Nếu bạn có thể đạt được một cái gì đó đơn giản thông qua cơ sở dữ liệu sql thì tốt hơn hết là vì db sẽ hoạt động tốt hơn nhiều và thực hiện tính toán ở đó và sau đó với kết quả tìm nạp. Tuy nhiên, nếu tính toán thực tế đòi hỏi quá nhiều tính toán từ đây và có những thứ thì bạn có thể đi với mã ứng dụng. Tại sao? Bởi vì kịch bản giống như lặp trong hầu hết các trường hợp không được xử lý tốt nhất bởi sql trong đó các ngôn ngữ giao diện người dùng được thiết kế tốt hơn cho những điều này.
  2. Trong trường hợp tính toán tương tự được yêu cầu từ nhiều nơi thì rõ ràng đặt mã tính toán ở cuối db sẽ tốt hơn để giữ mọi thứ ở cùng một nơi.
  3. Nếu có rất nhiều phép tính được thực hiện để đạt được kết quả cuối cùng thông qua nhiều truy vấn khác nhau thì bạn cũng nên kết thúc db vì bạn có thể đặt cùng một mã trong một quy trình được lưu trữ để thực hiện tốt hơn là lấy kết quả từ phụ trợ và sau đó tính toán chúng ở phía trước kết thúc.

Có nhiều khía cạnh khác mà bạn có thể suy nghĩ trước khi quyết định nơi đặt mã. Một nhận thức là hoàn toàn sai - Mọi thứ có thể được thực hiện tốt nhất bằng Java (mã ứng dụng) và / hoặc mọi thứ tốt nhất được thực hiện bởi db (mã sql).


0

Hình thành quan điểm hiệu suất: Đây là một hoạt động số học rất đơn giản mà gần như chắc chắn có thể được thực hiện nhanh hơn nhiều so với thực sự tìm nạp dữ liệu từ các đĩa nằm dưới cơ sở dữ liệu. Ngoài ra, việc tính toán các giá trị trong mệnh đề where có thể sẽ rất nhanh trên bất kỳ thời gian chạy nào. Tóm lại, nút cổ chai phải là đĩa IO, không phải là tính toán của các giá trị.

Theo khả năng đọc, tôi nghĩ rằng nếu bạn sử dụng ORM, bạn nên thực hiện nó trong môi trường máy chủ ứng dụng của mình, vì ORM sẽ cho phép bạn làm việc với dữ liệu cơ bản rất dễ dàng, sử dụng các thao tác dựa trên thiết lập. Nếu bạn định viết SQL thô, không có gì sai khi thực hiện tính toán ở đó, SQL của bạn cũng sẽ trông đẹp hơn và dễ đọc hơn nếu được định dạng đúng.


0

Điều quan trọng, "hiệu suất" không được xác định.

Điều quan trọng nhất với tôi là thời gian dành cho nhà phát triển.

Viết truy vấn SQL. Nếu quá chậm hoặc DB trở thành nút cổ chai, hãy xem xét lại. Vào thời điểm đó, bạn sẽ có thể điểm chuẩn hai cách tiếp cận và đưa ra quyết định dựa trên dữ liệu thực có liên quan đến thiết lập của bạn (phần cứng và bất kỳ ngăn xếp nào bạn đang sử dụng).


0

Tôi không tin rằng sự khác biệt về hiệu suất có thể được lý giải nếu không có ví dụ và điểm chuẩn cụ thể, nhưng tôi có một cách khác:

Mà bạn có thể duy trì tốt hơn? Ví dụ: bạn có thể muốn chuyển giao diện người dùng của mình từ Java sang Flash hoặc HTML5 hoặc C ++ hoặc một cái gì đó khác. Một số lượng lớn các chương trình đã trải qua một sự thay đổi như vậy, hoặc thậm chí tồn tại ở nhiều ngôn ngữ để bắt đầu, bởi vì chúng cần phải hoạt động trên nhiều thiết bị.

Ngay cả khi bạn có một lớp giữa thích hợp (từ ví dụ đã cho, có vẻ như không phải vậy), lớp đó có thể thay đổi và JBoss có thể trở thành Ruby / Rails.

Mặt khác, không chắc là bạn sẽ thay thế phụ trợ SQL bằng thứ gì đó không phải là DB quan hệ bằng SQL và ngay cả khi bạn làm thế, bạn sẽ phải viết lại giao diện người dùng từ đầu, vì vậy vấn đề là phải khắc phục.

Ý tưởng của tôi là nếu bạn thực hiện các phép tính trong DB, việc viết một mặt trước thứ hai hoặc lớp giữa sau sẽ dễ dàng hơn nhiều, vì bạn không phải thực hiện lại mọi thứ. Tuy nhiên, trong thực tế, tôi nghĩ rằng "nơi tôi có thể làm điều này với mã mà mọi người sẽ hiểu" là yếu tố quan trọng nhất.


Nếu bạn đổi từ jboss sang ruby, rất có thể bạn sẽ thay đổi db (và dù sao bạn cũng sẽ cần phải áp dụng các tính toán này) và không có khả năng là bạn có thể thay đổi sang một thứ khác, như nosql.
Dainius

0

Để đơn giản hóa cách trả lời này sẽ là xem xét cân bằng tải. Bạn muốn đặt tải ở nơi bạn có công suất lớn nhất (nếu nó có ý nghĩa gì). Trong hầu hết các hệ thống, máy chủ SQL nhanh chóng trở thành nút cổ chai, vì vậy câu trả lời có lẽ là bạn không muốn SQL thực hiện một công việc nhiều hơn mức cần thiết.

Ngoài ra, trong hầu hết các kiến ​​trúc, máy chủ SQL tạo nên cốt lõi của hệ thống và các hệ thống bên ngoài được thêm vào.

Nhưng toán học ở trên rất tầm thường đến nỗi trừ khi bạn đẩy hệ thống của mình đến giới hạn nơi tốt nhất để đặt nó là nơi bạn muốn đặt nó. Nếu toán học không tầm thường như tính sin / cos / tan để tính toán khoảng cách thì nỗ lực có thể trở nên không tầm thường và cần lập kế hoạch và kiểm tra cẩn thận.


0

Các câu trả lời khác cho câu hỏi này là thú vị. Đáng ngạc nhiên, không ai trả lời câu hỏi của bạn. Bạn đang tự hỏi:

  1. Có tốt hơn để truyền tới Cents trong truy vấn không? Tôi không nghĩ rằng các diễn viên để xu thêm bất cứ điều gì trong truy vấn của bạn.
  2. Có tốt hơn để sử dụng now () trong truy vấn không? Tôi muốn chuyển ngày vào truy vấn thay vì tính toán chúng trong truy vấn.

Thông tin thêm: Đối với câu hỏi bạn muốn chắc chắn rằng tổng hợp các phân số hoạt động mà không làm tròn lỗi. Tôi nghĩ rằng số 19,2 là hợp lý cho tiền và trong trường hợp thứ hai, số nguyên là OK. Sử dụng một float cho tiền là sai vì lý do này.

Đối với câu hỏi thứ hai, tôi muốn có toàn quyền kiểm soát với tư cách là một lập trình viên về ngày nào được coi là ngay bây giờ. Có thể khó viết các bài kiểm tra đơn vị tự động khi sử dụng các hàm như now (). Ngoài ra, khi bạn có tập lệnh giao dịch dài hơn, có thể tốt để đặt biến bằng với bây giờ () và sử dụng biến để tất cả logic sử dụng cùng một giá trị.


0

Hãy để tôi lấy một ví dụ thực tế để giải quyết câu hỏi này

Tôi cần tính trung bình di chuyển có trọng số trên dữ liệu ohlc của mình, tôi có khoảng 134000 cây nến với một biểu tượng cho mỗi cái để làm như vậy

  1. Tùy chọn 1 Thực hiện trong Python / Node, v.v.
  2. Tùy chọn 2 Thực hiện bằng chính SQL!

Cái nào tốt hơn?

  • Về cơ bản, nếu tôi phải làm điều này bằng Python, tôi sẽ phải tìm nạp tất cả các bản ghi được lưu trữ ở mức tồi tệ nhất, thực hiện tính toán và lưu lại mọi thứ mà theo tôi là một sự lãng phí rất lớn của IO
  • Thay đổi trung bình di chuyển có trọng số mỗi khi bạn nhận được một cây nến mới có nghĩa là tôi sẽ thực hiện một lượng lớn IO trong khoảng thời gian đều đặn không phải là ý kiến ​​hay trong dấu hiệu của tôi
  • Trong SQL, tất cả những gì tôi phải làm có lẽ là viết một trình kích hoạt tính toán và lưu trữ mọi thứ, do đó chỉ cần tìm nạp các giá trị WMA cuối cùng cho mỗi cặp mỗi giờ và điều đó hiệu quả hơn rất nhiều

Yêu cầu

  • Nếu tôi phải tính toán WMA cho mỗi cây nến và lưu trữ nó, tôi sẽ làm điều đó trên Python
  • Nhưng vì tôi chỉ cần giá trị cuối cùng, SQL nhanh hơn nhiều so với Python

Để khuyến khích bạn, đây là phiên bản Python để làm trung bình di chuyển có trọng số

WMA được thực hiện thông qua mã

import psycopg2
import psycopg2.extras
from talib import func
import timeit
import numpy as np
with psycopg2.connect('dbname=xyz user=xyz') as conn:
with conn.cursor() as cur:
t0 = timeit.default_timer()
cur.execute('select distinct symbol from ohlc_900 order by symbol')
for symbol in cur.fetchall():
cur.execute('select c from ohlc_900 where symbol = %s order by ts', symbol)
ohlc = np.array(cur.fetchall(), dtype = ([('c', 'f8')]))
wma = func.WMA(ohlc['c'], 10)
# print(*symbol, wma[-1])
print(timeit.default_timer() - t0)
conn.close()

WMA thông qua SQL

"""
if the period is 10
then we need 9 previous candles or 15 x 9 = 135 mins on the interval department
we also need to start counting at row number - (count in that group - 10)
For example if AAPL had 134 coins and current row number was 125
weight at that row will be weight = 125 - (134 - 10) = 1
10 period WMA calculations
Row no Weight c
125 1
126 2
127 3
128 4
129 5
130 6
131 7
132 8
133 9
134 10
"""
query2 = """
WITH
condition(sym, maxts, cnt) as (
select symbol, max(ts), count(symbol) from ohlc_900 group by symbol
),
cte as (
select symbol, ts,
case when cnt >= 10 and ts >= maxts - interval '135 mins'
then (row_number() over (partition by symbol order by ts) - (cnt - 10)) * c
else null
end as weighted_close
from ohlc_900
INNER JOIN condition
ON symbol = sym
WINDOW
w as (partition by symbol order by ts rows between 9 preceding and current row)
)
select symbol, sum(weighted_close)/55 as wma
from cte
WHERE weighted_close is NOT NULL
GROUP by symbol ORDER BY symbol
"""
with psycopg2.connect('dbname=xyz user=xyz') as conn:
with conn.cursor() as cur:
t0 = timeit.default_timer()
cur.execute(query2)
# for i in cur.fetchall():
# print(*i)
print(timeit.default_timer() - t0)
conn.close()

Dù bạn có tin hay không, truy vấn sẽ chạy nhanh hơn phiên bản Pure Python khi thực hiện AVERAGE MOVING MOVING !!!Tôi đã từng bước viết ra truy vấn đó để chờ vào đó và bạn sẽ làm tốt

Tốc độ

0,42141127300055814 giây Python

0,23801879299935536 giây SQL

Tôi có 134000 bản ghi OHLC giả trong cơ sở dữ liệu của tôi được chia cho 1000 cổ phiếu để đó là một ví dụ về nơi SQL có thể vượt trội hơn máy chủ ứng dụng của bạn


1
Tuy nhiên, nếu bạn cần thực hiện việc này hàng triệu lần càng nhanh càng tốt, việc tạo ra các ứng dụng python song song sẽ dễ dàng hơn nhiều so với bản sao db. Cho đến khi một thang đo nhất định dựa vào SQL chắc chắn nhanh hơn / rẻ hơn, nhưng cuối cùng cũng có một điểm bùng phát khi thực hiện phép tính này trong ứng dụng của bạn.
Lenny
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.