الانتقال إلى المحتوى الرئيسي

إنه يوم باي! لنحسب باي باستخدام SQL

عيد Pi سعيد! خطر لنا أن يكون من الممتع حساب pi باستخدام استعلامات SQL في ClickHouse. إليك ما توصّلنا إليه حتى الآن…
  1. يستخدم هذا المثال دالة الجدول numbers_mt في ClickHouse لإرجاع مليار صف، ولا يستغرق سوى 40 ملّي ثانية لحساب النتيجة:
SELECT 4 * sum(if(number % 2, -1, 1) / ((number * 2) + 1)) AS pi
FROM numbers_mt(1000000000.)

┌────────────────pi─┐
3.141592652589797
└───────────────────┘

1 row in set. Elapsed: 0.432 sec. Processed 1.00 billion rows, 8.00 GB (2.32 billion rows/s., 18.53 GB/s.)
  1. يعالج المثال التالي أيضًا مليار رقم، ولكن ليس بهذه السرعة:
SELECT 3 + (4 * sum(if((number % 2) = 0, if((number % 4) = 0, -1 / ((number * (number + 1)) * (number + 2)), 1 / ((number * (number + 1)) * (number + 2))), 0))) AS pi
FROM numbers_mt(2, 10000000000)

┌─────────────────pi─┐
3.1415926525808087
└────────────────────┘

1 row in set. Elapsed: 9.825 sec. Processed 10.00 billion rows, 80.00 GB (1.02 billion rows/s., 8.14 GB/s.)
  1. هذا بلا شك خيارنا المفضل في ClickHouse (وهو الأدق!):
SELECT pi()

┌──────────────pi()─┐
3.141592653589793
└───────────────────┘

1 row in set. Elapsed: 0.008 sec.
  1. يبدو أن أحدهم كان يعرف حساب المثلثات جيدًا في هذه المسألة:
SELECT 2 * asin(1) AS pi

┌────────────────pi─┐
3.141592653589793
└───────────────────┘

1 row in set. Elapsed: 0.005 sec.
  1. إليك واجهة برمجة تطبيقات مفيدة تتيح لك تحديد عدد الأرقام التي تريدها:
SELECT *
FROM url('https://api.pi.delivery/v1/pi?start=0&numberOfDigits=100', 'JSONEachRow')

┌───────────────content─┐
3.1415926535897933e99 │
└───────────────────────┘

1 row in set. Elapsed: 0.556 sec.
  1. هذا ذكي - إذ يستخدم دوال المسافة في ClickHouse:
WITH random_points AS
    (
        SELECT (rand64(1) / pow(2, 64), rand64(2) / pow(2, 64)) AS point
        FROM numbers(1000000000)
    )
SELECT (4 * countIf(L2Norm(point) < 1)) / count() AS pi
FROM random_points

┌──────────pi─┐
3.141627208
└─────────────┘

1 row in set. Elapsed: 4.742 sec. Processed 1.00 billion rows, 8.00 GB (210.88 million rows/s., 1.69 GB/s.)
  1. إذا كنت فيزيائيًا، فسيعجبك هذا:
SELECT 22 / 7

┌─────divide(22, 7)─┐
3.142857142857143
└───────────────────┘
  1. طريقة غير مباشرة أخرى (اقترحها Alexey Milovidov) دقيقة حتى 7 منازل عشرية - وهي سريعة:
WITH
    10 AS length,
    (number / 1000000000.) * length AS x
SELECT pow((2 * length) * avg(exp(-(x * x))), 2) AS pi
FROM numbers_mt(1000000000.)

┌─────────────────pi─┐
3.1415926890388595
└────────────────────┘

1 row in set. Elapsed: 1.245 sec. Processed 1.00 billion rows, 8.00 GB (803.25 million rows/s., 6.43 GB/s.)
إذا كان لديك المزيد، فسنكون سعداء بمساهمتك بها. شكرًا!
آخر تعديل في ٢٩ يونيو ٢٠٢٦