เลือก n สุ่มแถวจากตาราง SQL Server


309

ฉันมีตาราง SQL Server ที่มีแถวประมาณ 50,000 แถว ฉันต้องการเลือกแถวประมาณ 5,000 แถวโดยการสุ่ม ฉันคิดว่าวิธีที่ซับซ้อนการสร้างตาราง temp ด้วยคอลัมน์ "หมายเลขสุ่ม" คัดลอกตารางของฉันลงในนั้นวนลูปผ่านตาราง temp และอัปเดตแต่ละแถวด้วยRAND()แล้วเลือกจากตารางนั้นซึ่งคอลัมน์สุ่มหมายเลข < 0.1 ฉันกำลังมองหาวิธีที่ง่ายกว่าที่จะทำในงบเดียวถ้าเป็นไปได้

บทความนี้แนะนำให้ใช้NEWID()ฟังก์ชั่น ดูเหมือนว่าจะมีแนวโน้ม แต่ฉันไม่สามารถเห็นได้ว่าฉันจะเลือกเปอร์เซ็นต์ของแถวได้อย่างไร

มีใครเคยทำเช่นนี้มาก่อนหรือไม่ ความคิดใด ๆ


3
MSDN มีบทความที่ดีที่ครอบคลุมปัญหาเหล่านี้มากมาย: การเลือกแถวแบบสุ่มจากตารางขนาดใหญ่
KyleMit

คำตอบ:


387
select top 10 percent * from [yourtable] order by newid()

ในการตอบกลับความคิดเห็น "ถังขยะบริสุทธิ์" ที่เกี่ยวข้องกับตารางขนาดใหญ่: คุณสามารถทำเช่นนี้เพื่อปรับปรุงประสิทธิภาพ

select  * from [yourtable] where [yourPk] in 
(select top 10 percent [yourPk] from [yourtable] order by newid())

ค่าใช้จ่ายของสิ่งนี้คือการสแกนคีย์ของค่าบวกค่าเข้าร่วมซึ่งในตารางขนาดใหญ่ที่มีการเลือกเปอร์เซ็นต์เล็กน้อยควรสมเหตุสมผล


1
ฉันชอบวิธีนี้ดีกว่ามากแล้วใช้บทความที่เขาอ้างอิง
JoshBerke

14
เป็นเรื่องดีเสมอที่จะต้องทราบว่า newid () ไม่ใช่ตัวสร้างตัวเลขเทียมเทียมที่ดีจริง ๆ อย่างน้อยก็ไม่ดีเท่าแรนด์ () แต่ถ้าคุณต้องการตัวอย่างสุ่ม ๆ ราง ๆ และไม่สนใจคุณสมบัติทางคณิตศาสตร์และเช่นนั้นมันจะดีพอ มิฉะนั้นคุณต้อง: stackoverflow.com/questions/249301/ …
12861

1
อืมขอโทษถ้าเห็นได้ชัด .. แต่มัน[yourPk]หมายถึงอะไร? แก้ไข: Nvm คิดออก ... คีย์หลัก Durrr
Snailer

4
newid - guid ถูกออกแบบให้ไม่เหมือนใคร แต่ไม่สุ่ม .. วิธีการที่ไม่ถูกต้อง
Brans Ds

2
ด้วยแถวจำนวนมากเช่นnewid()ค่าใช้จ่ายในการเรียงลำดับ I / O มากกว่า 1 ล้านค่าจะสูงมากและจะส่งผลต่อประสิทธิภาพ
aadi1295

81

ขึ้นอยู่กับความต้องการของคุณคุณTABLESAMPLEจะได้รับการสุ่มและประสิทธิภาพที่ดีขึ้น สิ่งนี้มีอยู่ในเซิร์ฟเวอร์ MS SQL 2005 และใหม่กว่า

TABLESAMPLE จะคืนค่าข้อมูลจากหน้าสุ่มแทนที่จะเป็นแถวสุ่มดังนั้นจึงไม่สามารถเรียกคืนข้อมูลที่จะไม่ส่งคืนได้

ฉันทดสอบบนโต๊ะที่มีขนาดใหญ่มาก

select top 1 percent * from [tablename] order by newid()

ใช้เวลามากกว่า 20 นาที

select * from [tablename] tablesample(1 percent)

ใช้เวลา 2 นาที

ผลการดำเนินงานยังจะปรับปรุงในตัวอย่างที่มีขนาดเล็กในขณะที่มันจะไม่ได้อยู่กับTABLESAMPLEnewid()

โปรดทราบว่านี่ไม่ใช่newid()วิธีการสุ่มแบบสุ่มแต่จะให้ตัวอย่างที่ดี

ดูหน้า MSDN


7
ดังที่ Rob Boek ระบุไว้ด้านล่างผลลัพธ์จากการสุ่มตัวอย่างเป็นกลุ่มจึงไม่ใช่วิธีที่ดีในการรับผลการสุ่มจำนวนเล็กน้อย
Oskar Austegard

คุณคำนึงถึงคำถามว่าวิธีนี้ทำงานอย่างไร: เลือก top 1 percent * จาก [tablename] ลำดับโดย newid () เนื่องจาก newid () ไม่ใช่คอลัมน์ใน [tablename] เซิร์ฟเวอร์ sql ต่อท้ายคอลัมน์ newid () ในแต่ละแถวแล้วเรียงลำดับหรือไม่
FrenkyB

ตัวอย่างตารางเป็นคำตอบที่ดีที่สุดสำหรับฉันเมื่อฉันทำแบบสอบถามที่ซับซ้อนบนตารางที่มีขนาดใหญ่มาก ไม่มีคำถามว่ามันเร็วอย่างน่าทึ่ง ฉันได้รับความแปรปรวนในบันทึกหมายเลขที่ส่งคืนเนื่องจากฉันใช้งานหลายครั้ง แต่ทั้งหมดอยู่ในระยะขอบที่ยอมรับได้ของข้อผิดพลาด
jessier3

38

newid () / order by จะทำงานได้ แต่จะมีราคาแพงมากสำหรับชุดผลลัพธ์ขนาดใหญ่เพราะต้องสร้างรหัสสำหรับทุกแถวแล้วเรียงลำดับ

TABLESAMPLE () เป็นสิ่งที่ดีจากจุดยืนด้านประสิทธิภาพ แต่คุณจะได้รับผลลัพธ์จำนวนมาก (แถวทั้งหมดในหน้าจะถูกส่งคืน)

สำหรับตัวอย่างสุ่มจริงที่มีประสิทธิภาพดีกว่าวิธีที่ดีที่สุดคือกรองแถวแบบสุ่ม ฉันพบตัวอย่างโค้ดต่อไปนี้ในบทความ SQL Server Books Online การจำกัด ชุดผลลัพธ์โดยใช้ TABLESAMPLE :

หากคุณต้องการตัวอย่างแบบสุ่มของแต่ละแถวให้ปรับเปลี่ยนแบบสอบถามเพื่อกรองแถวแบบสุ่มแทนที่จะใช้ TABLESAMPLE ตัวอย่างเช่นแบบสอบถามต่อไปนี้ใช้ฟังก์ชัน NEWID เพื่อส่งกลับประมาณร้อยละหนึ่งของแถวของตาราง Sales.SalesOrderDetail:

SELECT * FROM Sales.SalesOrderDetail
WHERE 0.01 >= CAST(CHECKSUM(NEWID(),SalesOrderID) & 0x7fffffff AS float)
              / CAST (0x7fffffff AS int)

คอลัมน์ SalesOrderID จะรวมอยู่ในนิพจน์ CHECKSUM เพื่อให้ NEWID () ประเมินหนึ่งครั้งต่อแถวเพื่อให้ได้การสุ่มตัวอย่างตามแต่ละแถว นิพจน์ CAST (CHECKSUM (NEWID (), SalesOrderID) & 0x7fffffff AS float / CAST (0x7fffffff AS AS) ประเมินค่าเป็นทศนิยมแบบสุ่มระหว่าง 0 และ 1

เมื่อทำงานกับตารางที่มี 1,000,000 แถวนี่คือผลลัพธ์ของฉัน:

SET STATISTICS TIME ON
SET STATISTICS IO ON

/* newid()
   rows returned: 10000
   logical reads: 3359
   CPU time: 3312 ms
   elapsed time = 3359 ms
*/
SELECT TOP 1 PERCENT Number
FROM Numbers
ORDER BY newid()

/* TABLESAMPLE
   rows returned: 9269 (varies)
   logical reads: 32
   CPU time: 0 ms
   elapsed time: 5 ms
*/
SELECT Number
FROM Numbers
TABLESAMPLE (1 PERCENT)

/* Filter
   rows returned: 9994 (varies)
   logical reads: 3359
   CPU time: 641 ms
   elapsed time: 627 ms
*/    
SELECT Number
FROM Numbers
WHERE 0.01 >= CAST(CHECKSUM(NEWID(), Number) & 0x7fffffff AS float) 
              / CAST (0x7fffffff AS int)

SET STATISTICS IO OFF
SET STATISTICS TIME OFF

หากคุณสามารถใช้งาน TABLESAMPLE ได้มันจะให้ประสิทธิภาพที่ดีที่สุดแก่คุณ มิฉะนั้นใช้วิธี newid () / filter newid () / คำสั่งซื้อควรเป็นทางเลือกสุดท้ายหากคุณมีชุดผลลัพธ์จำนวนมาก


ฉันเห็นบทความนั้นและลองใช้กับโค้ดของฉันดูเหมือนว่าNewID()จะได้รับการประเมินเพียงครั้งเดียวแทนที่จะเป็นแบบต่อแถวซึ่งฉันไม่ชอบ ...
Andrew Mao

23

การเลือกแถวแบบสุ่มจากโต๊ะขนาดใหญ่บน MSDN มีวิธีการแก้ปัญหาที่เรียบง่ายและพูดชัดแจ้งซึ่งจัดการกับข้อกังวลด้านประสิทธิภาพขนาดใหญ่

  SELECT * FROM Table1
  WHERE (ABS(CAST(
  (BINARY_CHECKSUM(*) *
  RAND()) as int)) % 100) < 10

น่าสนใจมาก. หลังจากอ่านบทความฉันไม่เข้าใจจริง ๆ ว่าทำไมRAND()ไม่คืนค่าเดียวกันสำหรับแต่ละแถว (ซึ่งจะเอาชนะBINARY_CHECKSUM()ตรรกะ) เป็นเพราะมันถูกเรียกภายในฟังก์ชั่นอื่นแทนที่จะเป็นส่วนหนึ่งของส่วนคำสั่ง SELECT?
John M Gant

เคียวรีนี้รันบนตารางที่มีแถว 6 มม. ในเวลาน้อยกว่าหนึ่งวินาที
Mark Melville

2
ฉันใช้คำค้นหานี้บนโต๊ะที่มี 35 รายการและเก็บไว้สองชุดในชุดผลลัพธ์บ่อยมาก นี่อาจเป็นปัญหากับrand()หรือการรวมกันของด้านบน - แต่ฉันหันหน้าหนีจากการแก้ปัญหาด้วยเหตุผลนี้ จำนวนผลลัพธ์ต่าง ๆ จาก 1 ถึง 5 ดังนั้นสิ่งนี้อาจไม่เป็นที่ยอมรับในบางสถานการณ์
โอลิเวอร์

RAND () ไม่ส่งคืนค่าเดียวกันสำหรับทุกแถวหรือไม่
Sarsaparilla

RAND()ส่งคืนค่าเดียวกันสำหรับทุกแถว (ซึ่งเป็นสาเหตุที่โซลูชันนี้เร็ว) อย่างไรก็ตามแถวที่มีการตรวจสอบแบบไบนารีที่อยู่ใกล้กันมากมีความเสี่ยงสูงในการสร้างผลการตรวจสอบที่คล้ายกันทำให้เกิดการจับกันเป็นก้อนเมื่อRAND()มีขนาดเล็ก เช่น==(ABS(CAST((BINARY_CHECKSUM(111,null,null) * 0.1) as int))) % 100 SELECT (ABS(CAST((BINARY_CHECKSUM(113,null,null) * 0.1) as int))) % 100หากข้อมูลของคุณประสบปัญหานี้ให้คูณBINARY_CHECKSUMด้วย 9923
Brian

12

ลิงค์นี้มีการเปรียบเทียบที่น่าสนใจระหว่าง Orderby (NEWID ()) และวิธีอื่น ๆ สำหรับตารางที่มี 1, 7 และ 13 ล้านแถว

บ่อยครั้งเมื่อคำถามเกี่ยวกับวิธีเลือกแถวสุ่มถูกถามในกลุ่มสนทนาจะมีการเสนอคำถาม NEWID มันง่ายและทำงานได้ดีมากสำหรับตารางเล็ก ๆ

SELECT TOP 10 PERCENT *
  FROM Table1
  ORDER BY NEWID()

อย่างไรก็ตามแบบสอบถาม NEWID มีข้อเสียเปรียบอย่างมากเมื่อคุณใช้กับตารางขนาดใหญ่ ส่วนคำสั่ง ORDER BY ทำให้แถวทั้งหมดในตารางถูกคัดลอกลงในฐานข้อมูล tempdb ซึ่งเรียงลำดับไว้ ทำให้สองปัญหา:

  1. การดำเนินการเรียงลำดับมักจะมีค่าใช้จ่ายสูง การเรียงลำดับสามารถใช้ดิสก์ I / O จำนวนมากและสามารถรันเป็นเวลานาน
  2. ในสถานการณ์ที่เลวร้ายที่สุด tempdb อาจมีพื้นที่ว่างไม่พอ ในสถานการณ์สมมติที่ดีที่สุด tempdb สามารถใช้พื้นที่ดิสก์จำนวนมากที่จะไม่ถูกเรียกคืนโดยไม่มีคำสั่งย่อขนาดด้วยตนเอง

สิ่งที่คุณต้องการคือวิธีในการเลือกแถวแบบสุ่มซึ่งจะไม่ใช้ tempdb และจะไม่ช้าลงเมื่อตารางมีขนาดใหญ่ขึ้น นี่คือความคิดใหม่เกี่ยวกับวิธีการทำเช่นนั้น:

SELECT * FROM Table1
  WHERE (ABS(CAST(
  (BINARY_CHECKSUM(*) *
  RAND()) as int)) % 100) < 10

แนวคิดพื้นฐานที่อยู่เบื้องหลังแบบสอบถามนี้คือเราต้องการสร้างตัวเลขสุ่มระหว่าง 0 ถึง 99 สำหรับแต่ละแถวในตารางจากนั้นเลือกแถวทั้งหมดที่มีหมายเลขสุ่มน้อยกว่าค่าของเปอร์เซ็นต์ที่ระบุ ในตัวอย่างนี้เราต้องการประมาณ 10 เปอร์เซ็นต์ของแถวที่เลือกแบบสุ่ม ดังนั้นเราเลือกแถวทั้งหมดที่มีหมายเลขสุ่มน้อยกว่า 10

โปรดอ่านบทความเต็มรูปแบบในMSDN


2
สวัสดีผู้ค้นพบดีคุณอาจคัดค้านเนื่องจากลิงก์มีเพียงคำตอบเท่านั้นที่จะถูกลบ
bummi

1
@bummi ผมเปลี่ยนมันเพื่อหลีกเลี่ยงการเชื่อมโยงคำตอบ :)
QMaster

นี่คือคำตอบที่ดีที่สุด 'ORDER BY NEWID ()' ทำงานได้ในกรณีส่วนใหญ่ (ตารางที่เล็กกว่า) แต่เป็นมาตรฐานในลิงก์ refrenced แสดงให้เห็นอย่างชัดเจนว่ามันอยู่ข้างหลังเมื่อตารางเติบโตขึ้น
pedram bashiri

10

หากคุณ (แตกต่างจาก OP) ต้องการจำนวนเฉพาะของระเบียน (ซึ่งทำให้การตรวจสอบ CHECKSUM เข้าใกล้ยาก) และต้องการตัวอย่างแบบสุ่มมากกว่า TABLESAMPLE ที่จัดทำโดยตัวมันเองและต้องการความเร็วที่ดีกว่า CHECKSUM คุณอาจทำการผสานกับ TABLESAMPLE และ NEWID () วิธีการเช่นนี้

DECLARE @sampleCount int = 50
SET STATISTICS TIME ON

SELECT TOP (@sampleCount) * 
FROM [yourtable] TABLESAMPLE(10 PERCENT)
ORDER BY NEWID()

SET STATISTICS TIME OFF

ในกรณีของฉันนี่คือการประนีประนอมที่ตรงไปตรงมาที่สุดระหว่างการสุ่ม (ไม่ใช่ฉันรู้จริง) และความเร็ว แปรเปลี่ยน TABLESAMPLE เปอร์เซนต์ (หรือแถว) ตามความเหมาะสม - ยิ่งเปอร์เซ็นต์สูงยิ่งสุ่มตัวอย่างมากขึ้น แต่คาดว่าจะลดความเร็วเชิงเส้นลง (โปรดทราบว่า TABLESAMPLE จะไม่ยอมรับตัวแปร)


9

เพียงแค่สั่งตารางโดยจำนวนสุ่มและได้รับ 5,000 TOPแถวแรกที่ใช้

SELECT TOP 5000 * FROM [Table] ORDER BY newid();

UPDATE

แค่ลองใช้งานและnewid()โทรศัพท์ก็เพียงพอ - ไม่จำเป็นสำหรับนักแสดงทุกคนและคณิตศาสตร์ทั้งหมด


10
เหตุผลที่ใช้ 'การปลดเปลื้องและการคำนวณทั้งหมด' เพื่อประสิทธิภาพที่ดีขึ้น
hkf

6

นี่คือการรวมกันของความคิดเมล็ดเริ่มต้นและการตรวจสอบซึ่งดูเหมือนว่าฉันจะให้ผลลัพธ์ที่สุ่มอย่างถูกต้องโดยไม่ต้องเสียค่าใช้จ่ายของ NEWID ():

SELECT TOP [number] 
FROM table_name
ORDER BY RAND(CHECKSUM(*) * RAND())

3

ใน MySQL คุณสามารถทำได้:

SELECT `PRIMARY_KEY`, rand() FROM table ORDER BY rand() LIMIT 5000;

3
สิ่งนี้จะไม่ทำงาน เนื่องจากคำสั่ง select เป็นอะตอมมันจะสุ่มตัวเลขเพียงหนึ่งหมายเลขและทำซ้ำสำหรับแต่ละแถว คุณจะต้องดำเนินการใหม่ในแต่ละแถวเพื่อบังคับให้เปลี่ยน
Tom H

4
อืม ... รักความแตกต่างของผู้ขาย Select is atomic บน MySQL แต่ฉันคิดว่าต่างกัน สิ่งนี้จะทำงานใน MySQL
Jeff Ferland

2

ยังไม่เห็นความแตกต่างนี้ในคำตอบ ฉันมีข้อ จำกัด เพิ่มเติมที่ฉันต้องการกำหนดเมล็ดเริ่มต้นเพื่อเลือกชุดแถวเดียวกันในแต่ละครั้ง

สำหรับ MS SQL:

ตัวอย่างขั้นต่ำ:

select top 10 percent *
from table_name
order by rand(checksum(*))

เวลาดำเนินการปกติ: 1.00

ตัวอย่าง NewId ():

select top 10 percent *
from table_name
order by newid()

เวลาดำเนินการปกติ: 1.02

NewId()ช้ากว่าไม่มีนัยสำคัญrand(checksum(*))ดังนั้นคุณอาจไม่ต้องการใช้กับชุดบันทึกขนาดใหญ่

การคัดเลือกด้วยเมล็ดเริ่มต้น:

declare @seed int
set @seed = Year(getdate()) * month(getdate()) /* any other initial seed here */

select top 10 percent *
from table_name
order by rand(checksum(*) % @seed) /* any other math function here */

หากคุณต้องการเลือกชุดเดียวกันที่ได้รับเมล็ดดูเหมือนว่าจะทำงาน


มีข้อได้เปรียบในการใช้ @seed แบบพิเศษกับ RAND () หรือไม่
QMaster

แน่นอนคุณใช้พารามิเตอร์ของเมล็ดและเติมตามพารามิเตอร์วันที่ฟังก์ชั่น RAND () ทำเช่นเดียวกันยกเว้นการใช้ค่าเวลาที่สมบูรณ์ฉันต้องการทราบว่ามีประโยชน์ในการใช้พารามิเตอร์ที่สร้างขึ้นมีประโยชน์เช่นเมล็ดข้างต้น RAND () หรือไม่?
QMaster

อา!. ตกลงนี่เป็นข้อกำหนดของโครงการ ฉันต้องการสร้างรายการของแถวที่ไม่มีการสุ่มในลักษณะที่กำหนดไว้ โดยทั่วไปความเป็นผู้นำต้องการทราบว่าเราสุ่มเลือกแถวกี่แถวก่อนที่จะมีการเลือกและประมวลผลแถว ด้วยการสร้างค่าเมล็ดตามปี / เดือนฉันสามารถรับประกันการเรียกไปยังแบบสอบถามที่ปีนั้นจะกลับรายการ "สุ่ม" เดียวกัน ฉันรู้ว่ามันเป็นเรื่องแปลกและอาจจะมีวิธีที่ดีกว่า แต่ทำงาน ...
klyd

ฮ่าฮ่า :) ฉันเข้าใจแล้ว แต่ฉันคิดว่าความหมายทั่วไปของระเบียนที่เลือกแบบสุ่มนั้นไม่ใช่ระเบียนเดียวกันสำหรับคิวรีที่ทำงานอยู่
QMaster


0

มันจะปรากฏ newid () ไม่สามารถใช้ในตำแหน่งที่คำสั่งดังนั้นวิธีนี้ต้องใช้แบบสอบถามภายใน:

SELECT *
FROM (
    SELECT *, ABS(CHECKSUM(NEWID())) AS Rnd
    FROM MyTable
) vw
WHERE Rnd % 100 < 10        --10%

0

ฉันใช้มันในแบบสอบถามย่อยและมันส่งคืนแถวเดียวกันกับแบบสอบถามย่อย

 SELECT  ID ,
            ( SELECT TOP 1
                        ImageURL
              FROM      SubTable 
              ORDER BY  NEWID()
            ) AS ImageURL,
            GETUTCDATE() ,
            1
    FROM    Mytable

แล้วฉันแก้ไขด้วยการรวมตัวแปรตารางผู้ปกครองในที่

SELECT  ID ,
            ( SELECT TOP 1
                        ImageURL
              FROM      SubTable 
              Where Mytable.ID>0
              ORDER BY  NEWID()
            ) AS ImageURL,
            GETUTCDATE() ,
            1
    FROM    Mytable

โปรดทราบว่าเงื่อนไข


0

ไม่มีการระบุภาษาการประมวลผลฝั่งเซิร์ฟเวอร์ (เช่น PHP, .net ฯลฯ ) แต่ถ้าเป็น PHP ให้ดึงหมายเลขที่ต้องการ (หรือบันทึกทั้งหมด) และแทนที่การสุ่มในแบบสอบถามใช้ฟังก์ชันสับเปลี่ยนของ PHP ฉันไม่ทราบว่า. net มีฟังก์ชั่นที่เทียบเท่ากันหรือไม่

ORDER BY RAND () อาจมีการลงโทษประสิทธิภาพขึ้นอยู่กับจำนวนระเบียนที่เกี่ยวข้อง


ฉันจำไม่ได้ว่าสิ่งที่ฉันใช้สิ่งนี้ในเวลานั้น แต่ฉันอาจทำงานใน C # อาจอยู่บนเซิร์ฟเวอร์หรืออาจอยู่ในแอปพลิเคชันไคลเอนต์ไม่แน่ใจ C # ไม่มีอะไรที่เทียบได้กับการสับเปลี่ยนแบบ PHP ของ PHP โดยตรง แต่สามารถทำได้โดยการใช้ฟังก์ชั่นจากออบเจ็กต์แบบสุ่มภายในการดำเนินการแบบเลือกการเรียงลำดับผลลัพธ์ แต่เราต้องอ่านทั้งตารางจากดิสก์บนเซิร์ฟเวอร์ DB และส่งมันผ่านเครือข่ายเพียงเพื่อละ 90% ของข้อมูลนั้น การประมวลผลโดยตรงในฐานข้อมูลนั้นมีประสิทธิภาพมากกว่าแน่นอน
John M Gant

-2

สิ่งนี้ใช้ได้กับฉัน:

SELECT * FROM table_name
ORDER BY RANDOM()
LIMIT [number]

9
@ user537824 คุณลองบน SQL Server หรือไม่ RANDOM ไม่ใช่ฟังก์ชันและ LIMIT ไม่ใช่คำหลัก ไวยากรณ์ของ SQL Server สำหรับสิ่งที่คุณทำจะเป็นselect top 10 percent from table_name order by rand()เช่นนั้น แต่ก็ไม่ได้ผลเพราะ rand () จะส่งกลับค่าเดียวกันในทุกแถว
John M Gant
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.